mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Compare commits
585 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e349440ce0 | ||
|
|
d8a7fa978b | ||
|
|
d9988cc658 | ||
|
|
f38360e4f1 | ||
|
|
b149b87fa7 | ||
|
|
3d2aa988a0 | ||
|
|
f3d32da4cd | ||
|
|
d5059ed48c | ||
|
|
8b1e4cb21a | ||
|
|
6242afda42 | ||
|
|
4f44e6c7c7 | ||
|
|
6fec8c6d07 | ||
|
|
1348f9f5ef | ||
|
|
1b5a4bf369 | ||
|
|
426f914f4d | ||
|
|
caa11f9dfc | ||
|
|
d1ed22d3d3 | ||
|
|
67ea5edda6 | ||
|
|
8c6d5e2369 | ||
|
|
c5e05d2940 | ||
|
|
8adf3fe591 | ||
|
|
101c403138 | ||
|
|
5d1dbb27e1 | ||
|
|
390d6f3b51 | ||
|
|
29121913fd | ||
|
|
8d90663799 | ||
|
|
bc3cc4ce14 | ||
|
|
b5159c9776 | ||
|
|
9ee09319d7 | ||
|
|
7818582f3f | ||
|
|
0b7f79340b | ||
|
|
c22b5ce421 | ||
|
|
078b140966 | ||
|
|
c3e4e86c4e | ||
|
|
d0b1a9c822 | ||
|
|
e875cbbcbc | ||
|
|
663170681a | ||
|
|
b1318567e3 | ||
|
|
d1a02c52a9 | ||
|
|
b3efcd19db | ||
|
|
66e4e4e0a0 | ||
|
|
7c37fdb24e | ||
|
|
ceb1cc77d8 | ||
|
|
8df4726d22 | ||
|
|
408df5273d | ||
|
|
7a4d087be2 | ||
|
|
11a15ab5b1 | ||
|
|
f6ffd63b05 | ||
|
|
0afe9d2ef8 | ||
|
|
c02b95346f | ||
|
|
db33c561ab | ||
|
|
df2cfa1e57 | ||
|
|
d40e2c2ce2 | ||
|
|
215f3b9f44 | ||
|
|
766cf9ae72 | ||
|
|
26d808deb7 | ||
|
|
f9259c976d | ||
|
|
39c3285a0a | ||
|
|
57f3624ee7 | ||
|
|
5a4b656a74 | ||
|
|
bf7e13d923 | ||
|
|
dedec668e1 | ||
|
|
1e4013be98 | ||
|
|
76c3210788 | ||
|
|
4a99eff854 | ||
|
|
237dabce17 | ||
|
|
6f36f7624a | ||
|
|
1dea626422 | ||
|
|
c74cc539c9 | ||
|
|
910e32bb3e | ||
|
|
6ad3c862ce | ||
|
|
05819baf97 | ||
|
|
d84ba2aef5 | ||
|
|
ec9e7d94bc | ||
|
|
a800749b87 | ||
|
|
76fe83452e | ||
|
|
6d940503af | ||
|
|
0ea5b58b50 | ||
|
|
94c079815f | ||
|
|
11ab7a6cb6 | ||
|
|
7f67135e69 | ||
|
|
a1717bbf7a | ||
|
|
c99375364d | ||
|
|
94460ed7ab | ||
|
|
413332462f | ||
|
|
18386d57d6 | ||
|
|
f72045438e | ||
|
|
17f74c693c | ||
|
|
3fb87a4688 | ||
|
|
9205f6cab7 | ||
|
|
d0ee364fb9 | ||
|
|
3a80ad0632 | ||
|
|
93c353bbc6 | ||
|
|
9f883dccec | ||
|
|
ad3b697517 | ||
|
|
5f3097185e | ||
|
|
7ac7f7d424 | ||
|
|
ba58f4df6a | ||
|
|
297bfddf6c | ||
|
|
e4d0aca744 | ||
|
|
8b5ac226c3 | ||
|
|
cfc264fa33 | ||
|
|
9e12958ca6 | ||
|
|
8609fb9e97 | ||
|
|
9d6dda8b17 | ||
|
|
92b64f0f12 | ||
|
|
677fa71ba1 | ||
|
|
9f3f34ce70 | ||
|
|
2d2b6588b3 | ||
|
|
44fa266697 | ||
|
|
57f7ea6745 | ||
|
|
326c7e969a | ||
|
|
23f9b3b276 | ||
|
|
1e74deede3 | ||
|
|
2317ad94f5 | ||
|
|
58d1f2de96 | ||
|
|
de101b3576 | ||
|
|
9fbfc43655 | ||
|
|
e3e37023e8 | ||
|
|
63409b61ea | ||
|
|
c827e7725b | ||
|
|
0bcaed719b | ||
|
|
c77d73c460 | ||
|
|
9fc5d41e1b | ||
|
|
ac0cb9e9cb | ||
|
|
f961318035 | ||
|
|
52fa670293 | ||
|
|
d0c3e0ae8d | ||
|
|
0b2491ead5 | ||
|
|
1723d19882 | ||
|
|
416f96fe44 | ||
|
|
7b700b4a0c | ||
|
|
bde578fb9d | ||
|
|
c41dc490ed | ||
|
|
6d9e816d19 | ||
|
|
8f19afee88 | ||
|
|
784ec877d8 | ||
|
|
48c509ef54 | ||
|
|
0a5f06816d | ||
|
|
ecbeaf10ed | ||
|
|
c8e4918b4e | ||
|
|
4ab5609dbd | ||
|
|
cfe8eb62e7 | ||
|
|
f2ceb84969 | ||
|
|
039628d7e4 | ||
|
|
91fb4bc035 | ||
|
|
d89ccc3401 | ||
|
|
7ab9a37989 | ||
|
|
cf7054b6da | ||
|
|
758f9e8f2f | ||
|
|
fef21906f5 | ||
|
|
37ce6a69c1 | ||
|
|
aaed8fbd49 | ||
|
|
5fbac9d861 | ||
|
|
c54298709f | ||
|
|
b7d1637b18 | ||
|
|
015fa551b7 | ||
|
|
a681f0e5b3 | ||
|
|
281810dfbb | ||
|
|
38b8e65d53 | ||
|
|
74ccaa6cf1 | ||
|
|
4d2083df27 | ||
|
|
98068232a6 | ||
|
|
60711df671 | ||
|
|
c6b7c11418 | ||
|
|
ece8811293 | ||
|
|
8c95c491b9 | ||
|
|
45091565b4 | ||
|
|
7c0222189a | ||
|
|
a84c735761 | ||
|
|
946c5d4527 | ||
|
|
2ac6208302 | ||
|
|
0cd65c825c | ||
|
|
43d97a7b97 | ||
|
|
9923556212 | ||
|
|
0a65783637 | ||
|
|
b5bd7e0a26 | ||
|
|
82779d101b | ||
|
|
9c18d349dd | ||
|
|
8c74071e30 | ||
|
|
256e5079cf | ||
|
|
4263e86189 | ||
|
|
dadb0bb378 | ||
|
|
8ba25ca840 | ||
|
|
09ac04331f | ||
|
|
c21caa76d5 | ||
|
|
4073d8fc32 | ||
|
|
f8b7be8572 | ||
|
|
d6ab811de0 | ||
|
|
9fa6722f2b | ||
|
|
c51204e9cd | ||
|
|
74794d8610 | ||
|
|
16978f5acd | ||
|
|
71e24d0cb9 | ||
|
|
9a45f99b0e | ||
|
|
7f829f56a3 | ||
|
|
347531f4fe | ||
|
|
a1c33a0852 | ||
|
|
9cd441654e | ||
|
|
88c866a735 | ||
|
|
b11492c3f3 | ||
|
|
52e30b6323 | ||
|
|
1ebad806f9 | ||
|
|
51129d3b5d | ||
|
|
379e1cdcf0 | ||
|
|
0a8f76cfd4 | ||
|
|
a382698c32 | ||
|
|
d43002952c | ||
|
|
718f1d02c6 | ||
|
|
542de22550 | ||
|
|
327d458f00 | ||
|
|
5f206dd12e | ||
|
|
e18ce338e9 | ||
|
|
51e6255e9d | ||
|
|
7fa7e6c2cc | ||
|
|
710d154817 | ||
|
|
f354a10a81 | ||
|
|
8bb8135f41 | ||
|
|
e7b9968519 | ||
|
|
bfc58d51f2 | ||
|
|
c158022da5 | ||
|
|
9e010b0026 | ||
|
|
a085b09e07 | ||
|
|
37da4ab7fe | ||
|
|
c5945d784b | ||
|
|
16ca08446b | ||
|
|
b487350714 | ||
|
|
753b12b49e | ||
|
|
0d90cf9c20 | ||
|
|
658fd2916d | ||
|
|
ed4ea675fb | ||
|
|
2746fd7a67 | ||
|
|
a6b92c60b0 | ||
|
|
d4d36a65ec | ||
|
|
97df8ee12f | ||
|
|
2ab637b4e8 | ||
|
|
9a821b051f | ||
|
|
e2f09fc93d | ||
|
|
891d8e0468 | ||
|
|
494e31e41f | ||
|
|
b369ae6a2a | ||
|
|
5c22ef0192 | ||
|
|
d99cbb9c85 | ||
|
|
4f14f01830 | ||
|
|
930b5c701a | ||
|
|
bd9e2c47a3 | ||
|
|
53ca2cf881 | ||
|
|
55e17e7625 | ||
|
|
13b37aa2a9 | ||
|
|
fe4dde69ea | ||
|
|
0268a5a3ec | ||
|
|
4bddb529d4 | ||
|
|
435f5d1751 | ||
|
|
af8ce60dbe | ||
|
|
25f53232cd | ||
|
|
012cb518b3 | ||
|
|
2d1ffbc5b0 | ||
|
|
c88a6802a9 | ||
|
|
f5d608ac6a | ||
|
|
5d49bbfb29 | ||
|
|
5ce520a316 | ||
|
|
98c2c6e202 | ||
|
|
a2fc809d71 | ||
|
|
eb302aaef1 | ||
|
|
3b354f103a | ||
|
|
03c24a5d39 | ||
|
|
a8f13bb570 | ||
|
|
f8e35e0a72 | ||
|
|
27c153f5d3 | ||
|
|
82fdedfa14 | ||
|
|
f5bfbb13e2 | ||
|
|
80de578334 | ||
|
|
3b0acbe406 | ||
|
|
1062361612 | ||
|
|
7d81fe6f92 | ||
|
|
0285eca613 | ||
|
|
b0aea9ba89 | ||
|
|
b98eafb66f | ||
|
|
566df6793c | ||
|
|
4949e0a7f3 | ||
|
|
572dcdf1bb | ||
|
|
80ce825494 | ||
|
|
bdc3b1971c | ||
|
|
cee400a4c6 | ||
|
|
e58706d212 | ||
|
|
ad03caa064 | ||
|
|
e2d6189547 | ||
|
|
7b15d242f7 | ||
|
|
b81458d034 | ||
|
|
0595422f69 | ||
|
|
8e58adb279 | ||
|
|
a5e4b4d8e2 | ||
|
|
be2c010b5a | ||
|
|
e107326fee | ||
|
|
4da54f6dec | ||
|
|
1a3a955e10 | ||
|
|
3f304f7275 | ||
|
|
0690d742c7 | ||
|
|
43bbd4b4dd | ||
|
|
77fa27a698 | ||
|
|
8991e4f9f8 | ||
|
|
c9740651ba | ||
|
|
473550ba07 | ||
|
|
a7cbe91e73 | ||
|
|
40281f68b9 | ||
|
|
d3049751ba | ||
|
|
68164756c2 | ||
|
|
91c0ddef28 | ||
|
|
0641ca1b7b | ||
|
|
e3d9eb6ac9 | ||
|
|
7eec89bd53 | ||
|
|
289a7f8313 | ||
|
|
f49b2556ae | ||
|
|
318c43077c | ||
|
|
5691b68166 | ||
|
|
0ea44f988c | ||
|
|
59e2f796eb | ||
|
|
f1a75a98d0 | ||
|
|
76ac3fcf55 | ||
|
|
6cc3c8e84b | ||
|
|
36907c3244 | ||
|
|
dfeb02c1a7 | ||
|
|
6adf5f4090 | ||
|
|
e44ce3fb0b | ||
|
|
76ab69e44e | ||
|
|
57d009df5c | ||
|
|
b4d07b0b7e | ||
|
|
da3afa6f8e | ||
|
|
ec1c491e93 | ||
|
|
baccb556e8 | ||
|
|
eedfa61d74 | ||
|
|
2a9225178f | ||
|
|
259190e478 | ||
|
|
24a0c3b136 | ||
|
|
f46f2bc913 | ||
|
|
77f048c48e | ||
|
|
4055d51758 | ||
|
|
21eff5e1ba | ||
|
|
34174b442f | ||
|
|
77d37ab2a7 | ||
|
|
350fdbce9d | ||
|
|
e19cec4d3e | ||
|
|
e56d7665ed | ||
|
|
a0e23bfbe9 | ||
|
|
b7dc33f79e | ||
|
|
d8c31eec81 | ||
|
|
e84ee760b1 | ||
|
|
6ba1cc6bdb | ||
|
|
1b5e534592 | ||
|
|
1a3e21007b | ||
|
|
55e11ffb5c | ||
|
|
957a040996 | ||
|
|
460a42b135 | ||
|
|
8c356b401c | ||
|
|
820d06f008 | ||
|
|
3fa22fa716 | ||
|
|
333daa9cfb | ||
|
|
0e61460cdb | ||
|
|
268da18bb5 | ||
|
|
3fec29cbc6 | ||
|
|
4f3e79a4ac | ||
|
|
8b3699024b | ||
|
|
dd071f2538 | ||
|
|
ebe74dac17 | ||
|
|
909a51892f | ||
|
|
35c26bec0f | ||
|
|
8f05284792 | ||
|
|
e1d3af0734 | ||
|
|
c3fc5607ba | ||
|
|
a326d76f6a | ||
|
|
472fcab821 | ||
|
|
e7f81eb1aa | ||
|
|
31375855a0 | ||
|
|
385890d0f0 | ||
|
|
c9b4b5f18f | ||
|
|
c49af7fb33 | ||
|
|
4f042de2f4 | ||
|
|
f3e2b2ca40 | ||
|
|
a690447391 | ||
|
|
01593352ab | ||
|
|
0e4618529d | ||
|
|
57c97cd5e1 | ||
|
|
8606c0daa3 | ||
|
|
e94551d4f7 | ||
|
|
ffcd4f32ed | ||
|
|
2248f577df | ||
|
|
8a57553986 | ||
|
|
bb01ce776b | ||
|
|
631870846c | ||
|
|
a45abb7992 | ||
|
|
c7aaffa5e6 | ||
|
|
7def0d0b4e | ||
|
|
c035135fb7 | ||
|
|
15ffdeeeb8 | ||
|
|
74f6902a1b | ||
|
|
b2ae71333a | ||
|
|
fc88269f2d | ||
|
|
a191fcf803 | ||
|
|
37b109bd73 | ||
|
|
27b2a77f48 | ||
|
|
0f34dd0967 | ||
|
|
10fc717500 | ||
|
|
250068c6c2 | ||
|
|
488838752b | ||
|
|
dd0f4deae3 | ||
|
|
2df4106c92 | ||
|
|
ed58076c68 | ||
|
|
a4b300198d | ||
|
|
6980023c5a | ||
|
|
9f4d956345 | ||
|
|
ce4a90dc55 | ||
|
|
82ba193bb4 | ||
|
|
a3a004536d | ||
|
|
bb1d7e06c2 | ||
|
|
3689e6723c | ||
|
|
ef504c40b6 | ||
|
|
5e4a128d25 | ||
|
|
67d93d87b5 | ||
|
|
56b8b58606 | ||
|
|
97bc9343c1 | ||
|
|
18cea30f72 | ||
|
|
d5c048600e | ||
|
|
6d103d4ff9 | ||
|
|
7008197760 | ||
|
|
da66f33edc | ||
|
|
4109d1c825 | ||
|
|
a300663a9e | ||
|
|
cb33dac3b9 | ||
|
|
582bac8050 | ||
|
|
5e1c45bc09 | ||
|
|
b3073e6938 | ||
|
|
63e259689f | ||
|
|
d92ea0a39e | ||
|
|
81bbb4008b | ||
|
|
45ad0698b1 | ||
|
|
bc542a7bb1 | ||
|
|
efb065f558 | ||
|
|
00e63db029 | ||
|
|
f6a2926033 | ||
|
|
5b0f8afa4e | ||
|
|
c5b4421eae | ||
|
|
4d3f04e227 | ||
|
|
75ad29a68d | ||
|
|
62e1e65dda | ||
|
|
02f64314b8 | ||
|
|
12d7f191ee | ||
|
|
37135e1c8e | ||
|
|
85a0c25d0e | ||
|
|
1f081392df | ||
|
|
c02f9b827d | ||
|
|
7e95c9f999 | ||
|
|
4836b025e9 | ||
|
|
9a76838602 | ||
|
|
6c27186ce9 | ||
|
|
74c25c2ca3 | ||
|
|
91ee6ff6c0 | ||
|
|
05ba866bef | ||
|
|
af3aab86dc | ||
|
|
4370defb69 | ||
|
|
a105879c9a | ||
|
|
9383be678c | ||
|
|
7c8a394147 | ||
|
|
ffc8a9dae4 | ||
|
|
bb4a65882d | ||
|
|
5ebbb907e7 | ||
|
|
2ba66d7f91 | ||
|
|
7f8fe9e4f4 | ||
|
|
12292070ce | ||
|
|
8bc2b72ab0 | ||
|
|
208ae6b6d6 | ||
|
|
ba8121a8a7 | ||
|
|
c8da0427f9 | ||
|
|
fed13e8fda | ||
|
|
e3b977c636 | ||
|
|
337912f3d0 | ||
|
|
3b61f88343 | ||
|
|
5f6a6ba1c5 | ||
|
|
bb29844101 | ||
|
|
5600d95684 | ||
|
|
45ba341ccf | ||
|
|
7992526d2d | ||
|
|
9a6cb23659 | ||
|
|
bc132b7757 | ||
|
|
b05d726ad0 | ||
|
|
a7a612aa9b | ||
|
|
32a29c8bc7 | ||
|
|
23a3babf33 | ||
|
|
3d90f0b284 | ||
|
|
1e6448c61f | ||
|
|
a1f709ca12 | ||
|
|
a8ca2fd6e6 | ||
|
|
f835eeecdd | ||
|
|
70f5228d1c | ||
|
|
89e2ea610a | ||
|
|
6b68a983a5 | ||
|
|
4a2878b92e | ||
|
|
4f8165c8e1 | ||
|
|
855d15cec5 | ||
|
|
e1d17f61c4 | ||
|
|
380ae27762 | ||
|
|
4775dcd57a | ||
|
|
807ccc69ce | ||
|
|
aaee64ce02 | ||
|
|
294141e223 | ||
|
|
e3b125f244 | ||
|
|
7fd3297fed | ||
|
|
a2f54f67a3 | ||
|
|
d77724a911 | ||
|
|
1dc05ba196 | ||
|
|
cd7d4d102b | ||
|
|
0ba2450152 | ||
|
|
eee7d67591 | ||
|
|
760dbfa5b9 | ||
|
|
a52384de2e | ||
|
|
0dab8f0c94 | ||
|
|
629984c792 | ||
|
|
707e4c6dde | ||
|
|
efbe409399 | ||
|
|
faf0be6c53 | ||
|
|
1a078993f3 | ||
|
|
e0ac3bb853 | ||
|
|
c6cd13d9cd | ||
|
|
ef88e2e4a9 | ||
|
|
d9bcc39ee6 | ||
|
|
84f4a47df1 | ||
|
|
1408a5c357 | ||
|
|
202b15e8a8 | ||
|
|
110554a180 | ||
|
|
90e3715426 | ||
|
|
644fee2d1f | ||
|
|
c163effe60 | ||
|
|
0a39c746a3 | ||
|
|
2f46b3ff58 | ||
|
|
d35760d3a2 | ||
|
|
19a1101b43 | ||
|
|
8b209eaf27 | ||
|
|
fc6f7d3004 | ||
|
|
1abab9f92d | ||
|
|
c3b50983e3 | ||
|
|
a0857090a0 | ||
|
|
1ce9be3ed3 | ||
|
|
11d461380d | ||
|
|
6c0eb07c0b | ||
|
|
fb9ae3e78c | ||
|
|
52f59fbfb3 | ||
|
|
4a59017269 | ||
|
|
5c6d02de30 | ||
|
|
83b0e78b9e | ||
|
|
ac192e2416 | ||
|
|
52932d63d3 | ||
|
|
6a45e5d32c | ||
|
|
6f09598243 | ||
|
|
467e79d1c0 | ||
|
|
fa66c94ec3 | ||
|
|
2b4ce4b920 | ||
|
|
4e7585b87e | ||
|
|
de13db4627 | ||
|
|
ca8ceb428b | ||
|
|
c18597387a | ||
|
|
962504b788 | ||
|
|
8d1886d045 | ||
|
|
1c5167bb7c | ||
|
|
e248cca4e7 | ||
|
|
89ee97872d | ||
|
|
b22a2368d4 | ||
|
|
9ecfc57e44 | ||
|
|
cd141258c5 | ||
|
|
5dc027a9e2 | ||
|
|
3e55b0e417 | ||
|
|
9ca6b21c61 | ||
|
|
8ec528d4a0 | ||
|
|
961946bd29 | ||
|
|
da5fc860cf | ||
|
|
fdd39c4010 | ||
|
|
900e96a3a6 | ||
|
|
6a9f42f126 | ||
|
|
72ea196359 | ||
|
|
90a8abeed2 | ||
|
|
34fcbfa96f | ||
|
|
0f360cf892 | ||
|
|
22d4196bed | ||
|
|
fb9860d51d | ||
|
|
c8ba9d62aa | ||
|
|
4a66128af5 | ||
|
|
f061410205 |
33
.classpath
33
.classpath
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="bin/main" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="main"/>
|
||||
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin/main" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="main"/>
|
||||
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin/test" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="test"/>
|
||||
<attribute name="gradle_used_by_scope" value="test"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin/test" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="test"/>
|
||||
<attribute name="gradle_used_by_scope" value="test"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/Slime Java Commons"/>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
</classpath>
|
||||
12
.gitattributes
vendored
12
.gitattributes
vendored
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
|
||||
61
.github/workflows/gradle.yaml
vendored
Normal file
61
.github/workflows/gradle.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# This workflow will build a Java project with Gradle
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: SlimeVR Server
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "adopt"
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
|
||||
- name: Check code formatting
|
||||
run: ./gradlew spotlessCheck
|
||||
|
||||
- name: Test with Gradle
|
||||
run: ./gradlew test
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: "17"
|
||||
distribution: "adopt"
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew shadowJar
|
||||
|
||||
- name: Upload the Server JAR as a Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
# Artifact name
|
||||
name: "SlimeVR-Server" # optional, default is artifact
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: build/libs/*
|
||||
48
.github/workflows/gradle.yml
vendored
48
.github/workflows/gradle.yml
vendored
@@ -1,48 +0,0 @@
|
||||
# This workflow will build a Java project with Gradle
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: Build SlimeVR Server with Gradle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Clone Slime Java Commons
|
||||
uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
repository: Eirenliel/slime-java-commons
|
||||
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||
path: Slime Java Commons
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2.1.0
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Test with Gradle
|
||||
run: ./gradlew clean test
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew clean serverJar
|
||||
|
||||
- name: Upload the Server JAR as a Build Artifact
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
with:
|
||||
# Artifact name
|
||||
name: "SlimeVR-Server" # optional, default is artifact
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: build/libs/*
|
||||
28
.gitignore
vendored
28
.gitignore
vendored
@@ -6,7 +6,33 @@ build
|
||||
|
||||
/bin/
|
||||
|
||||
# Ignore .idea
|
||||
.idea
|
||||
|
||||
# Syncthing ignore file
|
||||
.stignore
|
||||
|
||||
MagnetoLib.dll
|
||||
MagnetoLib.dll
|
||||
vrconfig.yml
|
||||
|
||||
# BVH
|
||||
BVH Recordings
|
||||
|
||||
# AutoBone
|
||||
Recordings
|
||||
AutoBone Recordings
|
||||
Load AutoBone Recordings
|
||||
|
||||
# Logs
|
||||
*.log.*
|
||||
*.log.lck
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Ignore eclipse stuff
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
|
||||
# VSCode stuff
|
||||
/.vscode/settings.json
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "solarxr-protocol"]
|
||||
path = solarxr-protocol
|
||||
url = https://github.com/SlimeVR/SolarXR-Protocol.git
|
||||
23
.project
23
.project
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>SlimeVR Server</name>
|
||||
<comment>SlimeVR Server</comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,2 +0,0 @@
|
||||
connection.project.dir=
|
||||
eclipse.preferences.version=1
|
||||
@@ -1,2 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
@@ -1,2 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
line.separator=\r\n
|
||||
@@ -1,416 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
|
||||
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.APILeak=warning
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=info
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=info
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=error
|
||||
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=false
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=200
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=true
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
|
||||
@@ -1,3 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_Essentia
|
||||
formatter_settings_version=13
|
||||
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"richardwillis.vscode-spotless-gradle",
|
||||
"gaborv.flatbuffers",
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
75
CONTRIBUTING.md
Normal file
75
CONTRIBUTING.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Contributing to SlimeVR
|
||||
|
||||
This document describes essential knowledge for contributors to SlimeVR.
|
||||
|
||||
## How to get started
|
||||
|
||||
### Getting the code
|
||||
First, clone the codebase using `git`. If you don't have `git` installed, go install it.
|
||||
|
||||
```bash
|
||||
# Clone repositories
|
||||
git clone --recursive https://github.com/SlimeVR/SlimeVR-Server.git
|
||||
|
||||
# Enter the directory of the codebase
|
||||
cd SlimeVR-Server
|
||||
```
|
||||
|
||||
Now you can open the codebase in your favorite IDE or text editor.
|
||||
|
||||
### Building the code
|
||||
The code is built with `gradle`, a cli tool that manages java projects and their
|
||||
dependencies. You can build the code with `./gradlew build` and run it with
|
||||
`./gradlew run`.
|
||||
|
||||
|
||||
## Code Style
|
||||
Code is autoformatted with [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle).
|
||||
Code is checked for autoformatting whenever you build, but you can also run
|
||||
`./gradlew spotlessCheck` if you prefer.
|
||||
|
||||
To autoformat your code from the command line, you can run `./gradlew spotlessApply`.
|
||||
We recommend installing support for spotless in your IDE of choice, and formatting
|
||||
whenever you save a file, to make things easy.
|
||||
|
||||
If you need to prevent autoformatting for a particular region of code, use
|
||||
`// @formatter:off` and `// @formatter:on`
|
||||
|
||||
### Setting up spotless in VSCode
|
||||
* Install the `richardwillis.vscode-spotless-gradle` extension
|
||||
* Add the following to your workspace settings, at `.vscode/settings.json`:
|
||||
```json
|
||||
"spotlessGradle.format.enable": true,
|
||||
"editor.formatOnSave": true,
|
||||
"[java]": {
|
||||
"editor.defaultFormatter": "richardwillis.vscode-spotless-gradle"
|
||||
}
|
||||
```
|
||||
|
||||
### Setting up spotless for IntelliJ
|
||||
* Install https://plugins.jetbrains.com/plugin/18321-spotless-gradle.
|
||||
* Add a keyboard shortcut for `Code` > `Reformat Code with Spotless`
|
||||
* They are working on support to do this on save without a keybind
|
||||
[here](https://github.com/ragurney/spotless-intellij-gradle/issues/8)
|
||||
|
||||
### Setting up Eclipse autoformatting
|
||||
Import the formatting settings defined in `spotless.xml`, like this:
|
||||
* Go to `File > Properties`, then `Java Code Style > Formatter`
|
||||
* Check `Enable project specific settings`
|
||||
* Click `Import`, then open `spotless.xml`, then `Apply`
|
||||
* Go to `Java Editor > Save Actions`
|
||||
* Select `Enable project specific settings`, `Perform the selected actions on save`,
|
||||
`Format source code`, `Format all lines`
|
||||
|
||||
Eclipse will only do a subset of the checks in `spotless`, so you may still want to do
|
||||
`./gradlew spotlessApply` if you ever see an error from spotless.
|
||||
|
||||
## Code Licensing
|
||||
SlimeVR uses an MIT license, and some parts of the project use a dual MIT/Apache 2.0
|
||||
license. Be sure that any code that you reference, or dependencies you add, are
|
||||
compatible with these licenses. `GPL-v3` for example is not compatible because it
|
||||
requires any and all code that depends on it to *also* be licensed under `GPL-v3`.
|
||||
|
||||
## Discord
|
||||
We use discord *a lot* to coordinate and discuss development. Come join us at
|
||||
https://discord.gg/SlimeVR!
|
||||
42
LICENSE
42
LICENSE
@@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Eiren Rain
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Eiren Rain, SlimeVR
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
22
README.md
22
README.md
@@ -5,7 +5,7 @@ Server orchestrates communication between multiple sensors and integrations, lik
|
||||
|
||||
Sensors implementations:
|
||||
* [SlimeVR Tracker for ESP](https://github.com/SlimeVR/SlimeVR-Tracker-ESP) - ESP microcontrollers and multiple IMUs are supported
|
||||
* [owoTrack Mobile App](https://github.com/abb128/owoTrackVRSyncMobile) - use phone as a tracker (limited functionality and copmatibility)
|
||||
* [owoTrack Mobile App](https://github.com/abb128/owoTrackVRSyncMobile) - use phone as a tracker (limited functionality and compatibility)
|
||||
|
||||
Integrations:
|
||||
* Use [SlimeVR OpenVR Driver](https://github.com/SlimeVR/SlimeVR-OpenVR-Driver) as a driver for SteamVR
|
||||
@@ -13,4 +13,22 @@ Integrations:
|
||||
|
||||
## How to use
|
||||
|
||||
Latest instructions are currently [here](https://gist.github.com/Eirenliel/8c0eefcdbda1076d5c2e1bf634831d20). Will be updated and republished as time goes on.
|
||||
It's recommended to download installer from here: https://github.com/SlimeVR/SlimeVR-Installer/releases/latest/download/slimevr_web_installer.exe
|
||||
|
||||
Latest instructions are [on our site](https://docs.slimevr.dev/server-setup/slimevr-setup.html).
|
||||
|
||||
## License Clarification
|
||||
|
||||
**SlimeVR software** (including server, firmware, drivers, installator, documents, and others - see licence for each case specifically) **is distributed under the [MIT License](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE) and is copyright of Eiren Rain and SlimeVR.** The MIT Licence is a permissive license giving you rights to modify and distribute the software with little strings attached.
|
||||
|
||||
**However, the MIT License has some limits, and if you wish to distribute software based on SlimeVR, you need to be aware of them:**
|
||||
|
||||
* When distributing any software that uses or is based on SlimeVR, you have to provide to the end-user the original, unmodified `LICENSE` file from SlimeVR. This file is located [here](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE). This includes the `Copyright (c) 2021 Eiren Rain, SlimeVR` part of the license. It is not sufficient to use a generic MIT License, it must be the original license file.
|
||||
* This applies even if you distribute software without the source code. In this case, one way to provide it to the end-user is to have a menu in your application that lists all the open source licenses used, including SlimeVR's.
|
||||
|
||||
Please refer to the [LICENSE](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE) file if you are at any point uncertain what the exact the requirements are.
|
||||
|
||||
## Contributions
|
||||
By contributing to this project you are placing all your code under MIT or less restricting licenses, and you certify that the code you have used is compatible with those licenses or is authored by you. If you're doing so on your work time, you certify that your employer is okay with this.
|
||||
|
||||
For a how-to on contributing, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
118
build.gradle
118
build.gradle
@@ -7,43 +7,103 @@
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the java-library plugin to add support for Java Library
|
||||
id 'java-library'
|
||||
id 'application'
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
id "com.diffplug.spotless" version "6.5.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
// Set compiler to use UTF-8
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
compileTestJava.options.encoding = 'UTF-8'
|
||||
javadoc.options.encoding = 'UTF-8'
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
// if (JavaVersion.current().isJava9Compatible()) {
|
||||
// options.release = 8
|
||||
// }
|
||||
}
|
||||
tasks.withType(Test) {
|
||||
systemProperty('file.encoding', 'UTF-8')
|
||||
}
|
||||
tasks.withType(Javadoc) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':Slime Java Commons')
|
||||
implementation project(":solarxr-protocol")
|
||||
|
||||
// This dependency is exported to consumers, that is to say found on their compile classpath.
|
||||
api 'org.apache.commons:commons-math3:3.6.1'
|
||||
api 'org.yaml:snakeyaml:1.25'
|
||||
api 'net.java.dev.jna:jna:5.6.0'
|
||||
api 'net.java.dev.jna:jna-platform:5.6.0'
|
||||
api 'com.illposed.osc:javaosc-core:0.8'
|
||||
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
implementation 'com.google.guava:guava:28.2-jre'
|
||||
|
||||
|
||||
// Use JUnit test framework
|
||||
testImplementation 'junit:junit:4.12'
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
implementation group: 'com.google.flatbuffers', name: 'flatbuffers-java', version: '2.0.3'
|
||||
implementation group: 'commons-cli', name: 'commons-cli', version: '1.3.1'
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.6.1'
|
||||
implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.13.3'
|
||||
|
||||
implementation 'com.github.jonpeterson:jackson-module-model-versioning:1.2.2'
|
||||
implementation 'org.apache.commons:commons-math3:3.6.1'
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'net.java.dev.jna:jna:5.+'
|
||||
implementation 'net.java.dev.jna:jna-platform:5.+'
|
||||
implementation 'com.illposed.osc:javaosc-core:0.8'
|
||||
implementation 'com.fazecast:jSerialComm:2.+'
|
||||
implementation 'com.google.protobuf:protobuf-java:3.+'
|
||||
implementation 'org.java-websocket:Java-WebSocket:1.+'
|
||||
implementation 'com.melloware:jintellitype:1.+'
|
||||
|
||||
// Use JUnit test framework
|
||||
testImplementation platform('org.junit:junit-bom:5.9.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
subprojects.each { subproject -> evaluationDependsOn(subproject.path) }
|
||||
task serverJar (type: Jar, dependsOn: subprojects.tasks['build']) {
|
||||
manifest {
|
||||
attributes 'Main-Class': 'io.eiren.vr.Main'
|
||||
}
|
||||
|
||||
from {
|
||||
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
}
|
||||
with jar
|
||||
shadowJar {
|
||||
archiveBaseName.set('slimevr')
|
||||
archiveClassifier.set('')
|
||||
archiveVersion.set('')
|
||||
}
|
||||
application {
|
||||
getMainClass().set('dev.slimevr.Main')
|
||||
}
|
||||
|
||||
spotless {
|
||||
// optional: limit format enforcement to just the files changed by this feature branch
|
||||
// ratchetFrom 'origin/main'
|
||||
|
||||
format 'misc', {
|
||||
// define the files to apply `misc` to
|
||||
target '*.gradle', '*.md', '.gitignore'
|
||||
|
||||
// define the steps to apply to those files
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
indentWithTabs()
|
||||
}
|
||||
// format 'yaml', {
|
||||
// target '*.yml', '*.yaml',
|
||||
|
||||
// trimTrailingWhitespace()
|
||||
// endWithNewline()
|
||||
// indentWithSpaces(2) // YAML cannot contain tabs: https://yaml.org/faq.html
|
||||
// }
|
||||
java {
|
||||
removeUnusedImports()
|
||||
// Use eclipse JDT formatter
|
||||
eclipse().configFile("spotless.xml")
|
||||
}
|
||||
}
|
||||
|
||||
6
gradle.properties
Normal file
6
gradle.properties
Normal file
@@ -0,0 +1,6 @@
|
||||
# Fixes bug with spotless. See https://github.com/diffplug/spotless/issues/834#issuecomment-819118761
|
||||
org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
269
gradlew
vendored
Normal file → Executable file
269
gradlew
vendored
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,78 +17,113 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@@ -105,79 +140,95 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -54,7 +54,7 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
@@ -64,28 +64,14 @@ echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
665
java/com/jme3/math/ColorRGBA.java
Normal file
665
java/com/jme3/math/ColorRGBA.java
Normal file
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* *
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
import io.eiren.math.FloatMath;
|
||||
|
||||
|
||||
/**
|
||||
* <code>ColorRGBA</code> defines a color made from a collection of red, green
|
||||
* and blue values. An alpha value determines is transparency. All values must
|
||||
* be between 0 and 1. If any value is set higher or lower than these
|
||||
* constraints they are clamped to the min or max. That is, if a value smaller
|
||||
* than zero is set the value clamps to zero. If a value higher than 1 is
|
||||
* passed, that value is clamped to 1. However, because the attributes r, g, b,
|
||||
* a are public for efficiency reasons, they can be directly modified with
|
||||
* invalid values. The client should take care when directly addressing the
|
||||
* values. A call to clamp will assure that the values are within the
|
||||
* constraints.
|
||||
*
|
||||
* @author Mark Powell
|
||||
* @version $Id: ColorRGBA.java,v 1.29 2007/09/09 18:25:14 irrisor Exp $
|
||||
*/
|
||||
public final class ColorRGBA implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
/**
|
||||
* The color black (0,0,0).
|
||||
*/
|
||||
public static final ColorRGBA Black = new ColorRGBA(0f, 0f, 0f, 1f);
|
||||
/**
|
||||
* The color white (1,1,1).
|
||||
*/
|
||||
public static final ColorRGBA White = new ColorRGBA(1f, 1f, 1f, 1f);
|
||||
/**
|
||||
* The color gray (.2,.2,.2).
|
||||
*/
|
||||
public static final ColorRGBA DarkGray = new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
/**
|
||||
* The color gray (.5,.5,.5).
|
||||
*/
|
||||
public static final ColorRGBA Gray = new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
/**
|
||||
* The color gray (.8,.8,.8).
|
||||
*/
|
||||
public static final ColorRGBA LightGray = new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
|
||||
/**
|
||||
* The color red (1,0,0).
|
||||
*/
|
||||
public static final ColorRGBA Red = new ColorRGBA(1f, 0f, 0f, 1f);
|
||||
/**
|
||||
* The color green (0,1,0).
|
||||
*/
|
||||
public static final ColorRGBA Green = new ColorRGBA(0f, 1f, 0f, 1f);
|
||||
/**
|
||||
* The color blue (0,0,1).
|
||||
*/
|
||||
public static final ColorRGBA Blue = new ColorRGBA(0f, 0f, 1f, 1f);
|
||||
/**
|
||||
* The color yellow (1,1,0).
|
||||
*/
|
||||
public static final ColorRGBA Yellow = new ColorRGBA(1f, 1f, 0f, 1f);
|
||||
/**
|
||||
* The color magenta (1,0,1).
|
||||
*/
|
||||
public static final ColorRGBA Magenta = new ColorRGBA(1f, 0f, 1f, 1f);
|
||||
/**
|
||||
* The color cyan (0,1,1).
|
||||
*/
|
||||
public static final ColorRGBA Cyan = new ColorRGBA(0f, 1f, 1f, 1f);
|
||||
/**
|
||||
* The color orange (251/255, 130/255,0).
|
||||
*/
|
||||
public static final ColorRGBA Orange = new ColorRGBA(251f / 255f, 130f / 255f, 0f, 1f);
|
||||
/**
|
||||
* The color brown (65/255, 40/255, 25/255).
|
||||
*/
|
||||
public static final ColorRGBA Brown = new ColorRGBA(65f / 255f, 40f / 255f, 25f / 255f, 1f);
|
||||
/**
|
||||
* The color pink (1, 0.68, 0.68).
|
||||
*/
|
||||
public static final ColorRGBA Pink = new ColorRGBA(1f, 0.68f, 0.68f, 1f);
|
||||
/**
|
||||
* The black color with no alpha (0, 0, 0, 0).
|
||||
*/
|
||||
public static final ColorRGBA BlackNoAlpha = new ColorRGBA(0f, 0f, 0f, 0f);
|
||||
/**
|
||||
* The red component of the color. 0 is none and 1 is maximum red.
|
||||
*/
|
||||
public float r;
|
||||
/**
|
||||
* The green component of the color. 0 is none and 1 is maximum green.
|
||||
*/
|
||||
public float g;
|
||||
/**
|
||||
* The blue component of the color. 0 is none and 1 is maximum blue.
|
||||
*/
|
||||
public float b;
|
||||
/**
|
||||
* The alpha component of the color. 0 is transparent and 1 is opaque.
|
||||
*/
|
||||
public float a;
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>ColorRGBA</code> object. This color
|
||||
* is the default "white" with all values 1.
|
||||
*/
|
||||
public ColorRGBA() {
|
||||
r = g = b = a = 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>ColorRGBA</code> object. The values
|
||||
* are defined as passed parameters. These values are then clamped to insure
|
||||
* that they are between 0 and 1.
|
||||
*
|
||||
* @param r The red component of this color.
|
||||
* @param g The green component of this <code>ColorRGBA</code>.
|
||||
* @param b The blue component of this <code>ColorRGBA</code>.
|
||||
* @param a The alpha component of this <code>ColorRGBA</code>.
|
||||
*/
|
||||
public ColorRGBA(float r, float g, float b, float a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor creates a new <code>ColorRGBA</code> object, based on a
|
||||
* provided color.
|
||||
*
|
||||
* @param rgba The <code>ColorRGBA</code> object to copy.
|
||||
*/
|
||||
public ColorRGBA(ColorRGBA rgba) {
|
||||
this.a = rgba.a;
|
||||
this.r = rgba.r;
|
||||
this.g = rgba.g;
|
||||
this.b = rgba.b;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the RGBA values of this <code>ColorRGBA</code>. The
|
||||
* values are then clamped to insure that they are between 0 and 1.
|
||||
*
|
||||
* @param r The red component of this color.
|
||||
* @param g The green component of this color.
|
||||
* @param b The blue component of this color.
|
||||
* @param a The alpha component of this color.
|
||||
* @return this
|
||||
*/
|
||||
public ColorRGBA set(float r, float g, float b, float a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the values of this <code>ColorRGBA</code> to those
|
||||
* set by a parameter color.
|
||||
*
|
||||
* @param rgba The color to set this <code>ColorRGBA</code> to.
|
||||
* @return this
|
||||
*/
|
||||
public ColorRGBA set(ColorRGBA rgba) {
|
||||
if (rgba == null) {
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
a = 0;
|
||||
} else {
|
||||
r = rgba.r;
|
||||
g = rgba.g;
|
||||
b = rgba.b;
|
||||
a = rgba.a;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorRGBA setR(float r) {
|
||||
this.r = r;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorRGBA setG(float g) {
|
||||
this.g = g;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorRGBA setB(float b) {
|
||||
this.b = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColorRGBA setA(float a) {
|
||||
this.a = a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>clamp</code> insures that all values are between 0 and 1. If any
|
||||
* are less than 0 they are set to zero. If any are more than 1 they are set
|
||||
* to one.
|
||||
*/
|
||||
public void clamp() {
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
} else if (r > 1) {
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (g < 0) {
|
||||
g = 0;
|
||||
} else if (g > 1) {
|
||||
g = 1;
|
||||
}
|
||||
|
||||
if (b < 0) {
|
||||
b = 0;
|
||||
} else if (b > 1) {
|
||||
b = 1;
|
||||
}
|
||||
|
||||
if (a < 0) {
|
||||
a = 0;
|
||||
} else if (a > 1) {
|
||||
a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>getColorArray</code> retrieves the color values of this
|
||||
* <code>ColorRGBA</code> as a four element <code>float</code> array in the
|
||||
* order: r,g,b,a.
|
||||
*
|
||||
* @return The <code>float</code> array that contains the color components.
|
||||
*/
|
||||
public float[] getColorArray() {
|
||||
return new float[] { r, g, b, a };
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current r,g,b,a values into the given array. The given array
|
||||
* must have a length of 4 or greater, or an array index out of bounds
|
||||
* exception will be thrown.
|
||||
*
|
||||
* @param store The <code>float</code> array to store the values into.
|
||||
* @return The <code>float</code> array after storage.
|
||||
*/
|
||||
public float[] getColorArray(float[] store) {
|
||||
store[0] = r;
|
||||
store[1] = g;
|
||||
store[2] = b;
|
||||
store[3] = a;
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the alpha component value of this <code>ColorRGBA</code>.
|
||||
*
|
||||
* @return The alpha component value.
|
||||
*/
|
||||
public float getAlpha() {
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the red component value of this <code>ColorRGBA</code>.
|
||||
*
|
||||
* @return The red component value.
|
||||
*/
|
||||
public float getRed() {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the blue component value of this <code>ColorRGBA</code>.
|
||||
*
|
||||
* @return The blue component value.
|
||||
*/
|
||||
public float getBlue() {
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the green component value of this <code>ColorRGBA</code>.
|
||||
*
|
||||
* @return The green component value.
|
||||
*/
|
||||
public float getGreen() {
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from
|
||||
* this to the finalColor: this=(1-changeAmnt)*this + changeAmnt *
|
||||
* finalColor
|
||||
*
|
||||
* @param finalColor The final color to interpolate towards.
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
|
||||
* change from this towards finalColor.
|
||||
*/
|
||||
public void interpolate(ColorRGBA finalColor, float changeAmnt) {
|
||||
this.r = (1 - changeAmnt) * this.r + changeAmnt * finalColor.r;
|
||||
this.g = (1 - changeAmnt) * this.g + changeAmnt * finalColor.g;
|
||||
this.b = (1 - changeAmnt) * this.b + changeAmnt * finalColor.b;
|
||||
this.a = (1 - changeAmnt) * this.a + changeAmnt * finalColor.a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this <code>ColorRGBA</code> to the interpolation by changeAmnt from
|
||||
* beginColor to finalColor: this=(1-changeAmnt)*beginColor + changeAmnt *
|
||||
* finalColor
|
||||
*
|
||||
* @param beginColor The begining color (changeAmnt=0).
|
||||
* @param finalColor The final color to interpolate towards (changeAmnt=1).
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from beginColor towards finalColor.
|
||||
*/
|
||||
public void interpolate(ColorRGBA beginColor, ColorRGBA finalColor, float changeAmnt) {
|
||||
this.r = (1 - changeAmnt) * beginColor.r + changeAmnt * finalColor.r;
|
||||
this.g = (1 - changeAmnt) * beginColor.g + changeAmnt * finalColor.g;
|
||||
this.b = (1 - changeAmnt) * beginColor.b + changeAmnt * finalColor.b;
|
||||
this.a = (1 - changeAmnt) * beginColor.a + changeAmnt * finalColor.a;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>randomColor</code> is a utility method that generates a random
|
||||
* opaque color.
|
||||
*
|
||||
* @return a random <code>ColorRGBA</code> with an alpha set to 1.
|
||||
*/
|
||||
public static ColorRGBA randomColor() {
|
||||
ColorRGBA rVal = new ColorRGBA(0, 0, 0, 1);
|
||||
rVal.r = FastMath.nextRandomFloat();
|
||||
rVal.g = FastMath.nextRandomFloat();
|
||||
rVal.b = FastMath.nextRandomFloat();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the
|
||||
* corresponding r,g,b,a of the given color and returns the result as a new
|
||||
* <code>ColorRGBA</code>. Used as a way of combining colors and lights.
|
||||
*
|
||||
* @param c The color to multiply by.
|
||||
* @return The new <code>ColorRGBA</code>. this*c
|
||||
*/
|
||||
public ColorRGBA mult(ColorRGBA c) {
|
||||
return new ColorRGBA(c.r * r, c.g * g, c.b * b, c.a * a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given
|
||||
* scalar and returns the result as a new <code>ColorRGBA</code>. Used as a
|
||||
* way of making colors dimmer or brighter.
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @return The new <code>ColorRGBA</code>. this*scalar
|
||||
*/
|
||||
public ColorRGBA mult(float scalar) {
|
||||
return new ColorRGBA(scalar * r, scalar * g, scalar * b, scalar * a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies each r,g,b,a of this <code>ColorRGBA</code> by the given
|
||||
* scalar and returns the result (this). Used as a way of making colors
|
||||
* dimmer or brighter.
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @return this*c
|
||||
*/
|
||||
public ColorRGBA multLocal(float scalar) {
|
||||
this.r *= scalar;
|
||||
this.g *= scalar;
|
||||
this.b *= scalar;
|
||||
this.a *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each r,g,b,a of this <code>ColorRGBA</code> by the corresponding
|
||||
* r,g,b,a of the given color and returns the result as a new
|
||||
* <code>ColorRGBA</code>. Used as a way of combining colors and lights.
|
||||
*
|
||||
* @param c The color to add.
|
||||
* @return The new <code>ColorRGBA</code>. this+c
|
||||
*/
|
||||
public ColorRGBA add(ColorRGBA c) {
|
||||
return new ColorRGBA(c.r + r, c.g + g, c.b + b, c.a + a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each r,g,b,a of this <code>ColorRGBA</code> by the r,g,b,a the given
|
||||
* color and returns the result (this). Used as a way of combining colors
|
||||
* and lights.
|
||||
*
|
||||
* @param c The color to add.
|
||||
* @return this+c
|
||||
*/
|
||||
public ColorRGBA addLocal(ColorRGBA c) {
|
||||
set(c.r + r, c.g + g, c.b + b, c.a + a);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies alpha component by the given scalar and returns the result as
|
||||
* a new color.
|
||||
*/
|
||||
public ColorRGBA dilute(float scalarA) {
|
||||
return new ColorRGBA(r, g, b, a * scalarA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies alpha component by the given scalar and returns the result
|
||||
* (this).
|
||||
*/
|
||||
public ColorRGBA diluteLocal(float scalarA) {
|
||||
this.a *= scalarA;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>toString</code> returns the string representation of this
|
||||
* <code>ColorRGBA</code>. The format of the string is:<br>
|
||||
* <Class Name>: [R=RR.RRRR, G=GG.GGGG, B=BB.BBBB, A=AA.AAAA]
|
||||
*
|
||||
* @return The string representation of this <code>ColorRGBA</code>.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Color[" + r + ", " + g + ", " + b + ", " + a + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorRGBA clone() {
|
||||
try {
|
||||
return (ColorRGBA) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(); // can not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this <code>ColorRGBA</code> into the given <code>float</code>
|
||||
* array.
|
||||
*
|
||||
* @param floats The <code>float</code> array to take this
|
||||
* <code>ColorRGBA</code>. If null, a new <code>float[4]</code> is created.
|
||||
* @return The array, with r,g,b,a float values in that order.
|
||||
*/
|
||||
public float[] toArray(float[] floats) {
|
||||
if (floats == null) {
|
||||
floats = new float[4];
|
||||
}
|
||||
floats[0] = r;
|
||||
floats[1] = g;
|
||||
floats[2] = b;
|
||||
floats[3] = a;
|
||||
return floats;
|
||||
}
|
||||
|
||||
public ColorRGBA fromArray(float[] floats) {
|
||||
r = floats[0];
|
||||
g = floats[1];
|
||||
b = floats[2];
|
||||
a = floats[3];
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>equals</code> returns true if this <code>ColorRGBA</code> is
|
||||
* logically equivalent to a given color. That is, if all the components of
|
||||
* the two colors are the same. False is returned otherwise.
|
||||
*
|
||||
* @param o The object to compare against.
|
||||
* @return true if the colors are equal, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ColorRGBA)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ColorRGBA comp = (ColorRGBA) o;
|
||||
if (!FloatMath.equalsWithEpsilon(r, comp.r, FastMath.ZERO_TOLERANCE)) {
|
||||
return false;
|
||||
}
|
||||
if (!FloatMath.equalsWithEpsilon(g, comp.g, FastMath.ZERO_TOLERANCE)) {
|
||||
return false;
|
||||
}
|
||||
if (!FloatMath.equalsWithEpsilon(b, comp.b, FastMath.ZERO_TOLERANCE)) {
|
||||
return false;
|
||||
}
|
||||
if (!FloatMath.equalsWithEpsilon(a, comp.a, FastMath.ZERO_TOLERANCE)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>hashCode</code> returns a unique code for this
|
||||
* <code>ColorRGBA</code> based on its values. If two colors are logically
|
||||
* equivalent, they will return the same hash code value.
|
||||
*
|
||||
* @return The hash code value of this <code>ColorRGBA</code>.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 37;
|
||||
hash += 37 * hash + Float.floatToIntBits(r);
|
||||
hash += 37 * hash + Float.floatToIntBits(g);
|
||||
hash += 37 * hash + Float.floatToIntBits(b);
|
||||
hash += 37 * hash + Float.floatToIntBits(a);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the component values of this <code>ColorRGBA</code> as a four
|
||||
* element <code>byte</code> array in the order: r,g,b,a.
|
||||
*
|
||||
* @return the <code>byte</code> array that contains the color components.
|
||||
*/
|
||||
public byte[] asBytesRGBA() {
|
||||
byte[] store = new byte[4];
|
||||
store[0] = (byte) ((int) (r * 255) & 0xFF);
|
||||
store[1] = (byte) ((int) (g * 255) & 0xFF);
|
||||
store[2] = (byte) ((int) (b * 255) & 0xFF);
|
||||
store[3] = (byte) ((int) (a * 255) & 0xFF);
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the component values of this <code>ColorRGBA</code> as an
|
||||
* <code>int</code> in a,r,g,b order. Bits 24-31 are alpha, 16-23 are red,
|
||||
* 8-15 are green, 0-7 are blue.
|
||||
*
|
||||
* @return The integer representation of this <code>ColorRGBA</code> in
|
||||
* a,r,g,b order.
|
||||
*/
|
||||
public int asIntARGB() {
|
||||
int argb = (((int) (a * 255) & 0xFF) << 24)
|
||||
| (((int) (r * 255) & 0xFF) << 16)
|
||||
| (((int) (g * 255) & 0xFF) << 8)
|
||||
| (((int) (b * 255) & 0xFF));
|
||||
return argb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the component values of this <code>ColorRGBA</code> as an
|
||||
* <code>int</code> in r,g,b,a order. Bits 24-31 are red, 16-23 are green,
|
||||
* 8-15 are blue, 0-7 are alpha.
|
||||
*
|
||||
* @return The integer representation of this <code>ColorRGBA</code> in
|
||||
* r,g,b,a order.
|
||||
*/
|
||||
public int asIntRGBA() {
|
||||
int rgba = (((int) (r * 255) & 0xFF) << 24)
|
||||
| (((int) (g * 255) & 0xFF) << 16)
|
||||
| (((int) (b * 255) & 0xFF) << 8)
|
||||
| (((int) (a * 255) & 0xFF));
|
||||
return rgba;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the component values of this <code>ColorRGBA</code> as an
|
||||
* <code>int</code> in a,b,g,r order. Bits 24-31 are alpha, 16-23 are blue,
|
||||
* 8-15 are green, 0-7 are red.
|
||||
*
|
||||
* @return The integer representation of this <code>ColorRGBA</code> in
|
||||
* a,b,g,r order.
|
||||
*/
|
||||
public int asIntABGR() {
|
||||
int abgr = (((int) (a * 255) & 0xFF) << 24)
|
||||
| (((int) (b * 255) & 0xFF) << 16)
|
||||
| (((int) (g * 255) & 0xFF) << 8)
|
||||
| (((int) (r * 255) & 0xFF));
|
||||
return abgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the component values of this <code>ColorRGBA</code> with the given
|
||||
* combined ARGB <code>int</code>. Bits 24-31 are alpha, bits 16-23 are red,
|
||||
* bits 8-15 are green, bits 0-7 are blue.
|
||||
*
|
||||
* @param color The integer ARGB value used to set this
|
||||
* <code>ColorRGBA</code>.
|
||||
*/
|
||||
public void fromIntARGB(int color) {
|
||||
a = ((byte) (color >> 24) & 0xFF) / 255f;
|
||||
r = ((byte) (color >> 16) & 0xFF) / 255f;
|
||||
g = ((byte) (color >> 8) & 0xFF) / 255f;
|
||||
b = ((byte) (color) & 0xFF) / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RGBA values of this <code>ColorRGBA</code> with the given
|
||||
* combined RGBA value Bits 24-31 are red, bits 16-23 are green, bits 8-15
|
||||
* are blue, bits 0-7 are alpha.
|
||||
*
|
||||
* @param color The integer RGBA value used to set this object.
|
||||
*/
|
||||
public void fromIntRGBA(int color) {
|
||||
r = ((byte) (color >> 24) & 0xFF) / 255f;
|
||||
g = ((byte) (color >> 16) & 0xFF) / 255f;
|
||||
b = ((byte) (color >> 8) & 0xFF) / 255f;
|
||||
a = ((byte) (color) & 0xFF) / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform this <code>ColorRGBA</code> to a <code>Vector3f</code> using x
|
||||
* = r, y = g, z = b. The Alpha value is not used. This method is useful to
|
||||
* use for shaders assignment.
|
||||
*
|
||||
* @return A <code>Vector3f</code> containing the RGB value of this
|
||||
* <code>ColorRGBA</code>.
|
||||
*/
|
||||
public Vector3f toVector3f() {
|
||||
return new Vector3f(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform this <code>ColorRGBA</code> to a <code>Vector4f</code> using x
|
||||
* = r, y = g, z = b, w = a. This method is useful to use for shaders
|
||||
* assignment.
|
||||
*
|
||||
* @return A <code>Vector4f</code> containing the RGBA value of this
|
||||
* <code>ColorRGBA</code>.
|
||||
*/
|
||||
public Vector4f toVector4f() {
|
||||
return new Vector4f(r, g, b, a);
|
||||
}
|
||||
}
|
||||
1072
java/com/jme3/math/FastMath.java
Normal file
1072
java/com/jme3/math/FastMath.java
Normal file
File diff suppressed because it is too large
Load Diff
1362
java/com/jme3/math/Matrix3f.java
Normal file
1362
java/com/jme3/math/Matrix3f.java
Normal file
File diff suppressed because it is too large
Load Diff
2277
java/com/jme3/math/Matrix4f.java
Normal file
2277
java/com/jme3/math/Matrix4f.java
Normal file
File diff suppressed because it is too large
Load Diff
1721
java/com/jme3/math/Quaternion.java
Normal file
1721
java/com/jme3/math/Quaternion.java
Normal file
File diff suppressed because it is too large
Load Diff
399
java/com/jme3/math/Transform.java
Normal file
399
java/com/jme3/math/Transform.java
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
/**
|
||||
* Started Date: Jul 16, 2004<br>
|
||||
* <br>
|
||||
* Represents a translation, rotation and scale in one object.
|
||||
*
|
||||
* @author Jack Lindamood
|
||||
* @author Joshua Slack
|
||||
*/
|
||||
public final class Transform implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
|
||||
public static final Transform IDENTITY = new Transform();
|
||||
|
||||
private Quaternion rot = new Quaternion();
|
||||
private Vector3f translation = new Vector3f();
|
||||
private Vector3f scale = new Vector3f(1, 1, 1);
|
||||
|
||||
public Transform(Vector3f translation, Quaternion rot) {
|
||||
this.translation.set(translation);
|
||||
this.rot.set(rot);
|
||||
}
|
||||
|
||||
public Transform(Vector3f translation, Quaternion rot, Vector3f scale) {
|
||||
this(translation, rot);
|
||||
this.scale.set(scale);
|
||||
}
|
||||
|
||||
public Transform(Vector3f translation) {
|
||||
this(translation, Quaternion.IDENTITY);
|
||||
}
|
||||
|
||||
public Transform(Quaternion rot) {
|
||||
this(Vector3f.ZERO, rot);
|
||||
}
|
||||
|
||||
public Transform() {
|
||||
this(Vector3f.ZERO, Quaternion.IDENTITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this rotation to the given Quaternion value.
|
||||
*
|
||||
* @param rot The new rotation for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setRotation(Quaternion rot) {
|
||||
this.rot.set(rot);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this translation to the given value.
|
||||
*
|
||||
* @param trans The new translation for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setTranslation(Vector3f trans) {
|
||||
this.translation.set(trans);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the translation vector in this matrix.
|
||||
*
|
||||
* @return translation vector.
|
||||
*/
|
||||
public Vector3f getTranslation() {
|
||||
return translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this scale to the given value.
|
||||
*
|
||||
* @param scale The new scale for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(Vector3f scale) {
|
||||
this.scale.set(scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this scale to the given value.
|
||||
*
|
||||
* @param scale The new scale for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(float scale) {
|
||||
this.scale.set(scale, scale, scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scale vector in this matrix.
|
||||
*
|
||||
* @return scale vector.
|
||||
*/
|
||||
public Vector3f getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this translation value into the given vector3f. If trans is null,
|
||||
* a new vector3f is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param trans The store location for this matrix's translation.
|
||||
* @return The value of this matrix's translation.
|
||||
*/
|
||||
public Vector3f getTranslation(Vector3f trans) {
|
||||
if (trans == null)
|
||||
trans = new Vector3f();
|
||||
trans.set(this.translation);
|
||||
return trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this rotation value into the given Quaternion. If quat is null, a
|
||||
* new Quaternion is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param quat The store location for this matrix's rotation.
|
||||
* @return The value of this matrix's rotation.
|
||||
*/
|
||||
public Quaternion getRotation(Quaternion quat) {
|
||||
if (quat == null)
|
||||
quat = new Quaternion();
|
||||
quat.set(rot);
|
||||
return quat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rotation quaternion in this matrix.
|
||||
*
|
||||
* @return rotation quaternion.
|
||||
*/
|
||||
public Quaternion getRotation() {
|
||||
return rot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this scale value into the given vector3f. If scale is null, a new
|
||||
* vector3f is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param scale The store location for this matrix's scale.
|
||||
* @return The value of this matrix's scale.
|
||||
*/
|
||||
public Vector3f getScale(Vector3f scale) {
|
||||
if (scale == null)
|
||||
scale = new Vector3f();
|
||||
scale.set(this.scale);
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix to the interpolation between the first matrix and the
|
||||
* second by delta amount.
|
||||
*
|
||||
* @param t1 The begining transform.
|
||||
* @param t2 The ending transform.
|
||||
* @param delta An amount between 0 and 1 representing how far to
|
||||
* interpolate from t1 to t2.
|
||||
*/
|
||||
public void interpolateTransforms(Transform t1, Transform t2, float delta) {
|
||||
this.rot.slerp(t1.rot, t2.rot, delta);
|
||||
this.translation.interpolate(t1.translation, t2.translation, delta);
|
||||
this.scale.interpolate(t1.scale, t2.scale, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the values of this matrix acording to it's parent. Very similar
|
||||
* to the concept of Node/Spatial transforms.
|
||||
*
|
||||
* @param parent The parent matrix.
|
||||
* @return This matrix, after combining.
|
||||
*/
|
||||
public Transform combineWithParent(Transform parent) {
|
||||
scale.multLocal(parent.scale);
|
||||
// rot.multLocal(parent.rot);
|
||||
parent.rot.mult(rot, rot);
|
||||
|
||||
// This here, is evil code
|
||||
// parent
|
||||
// .rot
|
||||
// .multLocal(translation)
|
||||
// .multLocal(parent.scale)
|
||||
// .addLocal(parent.translation);
|
||||
|
||||
translation.multLocal(parent.scale);
|
||||
parent.rot
|
||||
.multLocal(translation)
|
||||
.addLocal(parent.translation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #combineWithParent(Transform)}, but assumes that rotation
|
||||
* is global, so it's not modified.
|
||||
*
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
public Transform combineWithParentGlobalRotation(Transform parent) {
|
||||
scale.multLocal(parent.scale);
|
||||
translation.multLocal(parent.scale);
|
||||
|
||||
parent.rot
|
||||
.multLocal(translation)
|
||||
.addLocal(parent.translation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix's translation to the given x,y,z values.
|
||||
*
|
||||
* @param x This matrix's new x translation.
|
||||
* @param y This matrix's new y translation.
|
||||
* @param z This matrix's new z translation.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setTranslation(float x, float y, float z) {
|
||||
translation.set(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix's scale to the given x,y,z values.
|
||||
*
|
||||
* @param x This matrix's new x scale.
|
||||
* @param y This matrix's new y scale.
|
||||
* @param z This matrix's new z scale.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(float x, float y, float z) {
|
||||
scale.set(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3f transformVector(final Vector3f in, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
|
||||
// multiply with scale first, then rotate, finally translate (cf.
|
||||
// Eberly)
|
||||
return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation);
|
||||
}
|
||||
|
||||
public Vector3f transformInverseVector(final Vector3f in, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
|
||||
// The author of this code should look above and take the inverse of
|
||||
// that
|
||||
// But for some reason, they didnt ..
|
||||
// in.subtract(translation, store).divideLocal(scale);
|
||||
// rot.inverse().mult(store, store);
|
||||
|
||||
in.subtract(translation, store);
|
||||
rot.inverse().mult(store, store);
|
||||
store.divideLocal(scale);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1.
|
||||
*/
|
||||
public void loadIdentity() {
|
||||
translation.set(0, 0, 0);
|
||||
scale.set(1, 1, 1);
|
||||
rot.set(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()
|
||||
+ "[ "
|
||||
+ translation.x
|
||||
+ ", "
|
||||
+ translation.y
|
||||
+ ", "
|
||||
+ translation.z
|
||||
+ "]\n"
|
||||
+ "[ "
|
||||
+ rot.x
|
||||
+ ", "
|
||||
+ rot.y
|
||||
+ ", "
|
||||
+ rot.z
|
||||
+ ", "
|
||||
+ rot.w
|
||||
+ "]\n"
|
||||
+ "[ "
|
||||
+ scale.x
|
||||
+ " , "
|
||||
+ scale.y
|
||||
+ ", "
|
||||
+ scale.z
|
||||
+ "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix to be equal to the given matrix.
|
||||
*
|
||||
* @param matrixQuat The matrix to be equal to.
|
||||
* @return this
|
||||
*/
|
||||
public Transform set(Transform matrixQuat) {
|
||||
this.translation.set(matrixQuat.translation);
|
||||
this.rot.set(matrixQuat.rot);
|
||||
this.scale.set(matrixQuat.scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((rot == null) ? 0 : rot.hashCode());
|
||||
result = prime * result + ((scale == null) ? 0 : scale.hashCode());
|
||||
result = prime * result + ((translation == null) ? 0 : translation.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Transform other = (Transform) obj;
|
||||
if (rot == null) {
|
||||
if (other.rot != null)
|
||||
return false;
|
||||
} else if (!rot.equals(other.rot))
|
||||
return false;
|
||||
if (scale == null) {
|
||||
if (other.scale != null)
|
||||
return false;
|
||||
} else if (!scale.equals(other.scale))
|
||||
return false;
|
||||
if (translation == null) {
|
||||
if (other.translation != null)
|
||||
return false;
|
||||
} else if (!translation.equals(other.translation))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transform clone() {
|
||||
try {
|
||||
Transform tq = (Transform) super.clone();
|
||||
tq.rot = rot.clone();
|
||||
tq.scale = scale.clone();
|
||||
tq.translation = translation.clone();
|
||||
return tq;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
718
java/com/jme3/math/Vector2f.java
Normal file
718
java/com/jme3/math/Vector2f.java
Normal file
@@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* <code>Vector2f</code> defines a Vector for a two float value vector.
|
||||
*
|
||||
* @author Mark Powell
|
||||
* @author Joshua Slack
|
||||
*/
|
||||
public final class Vector2f implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
private static final Logger logger = Logger.getLogger(Vector2f.class.getName());
|
||||
|
||||
public static final Vector2f ZERO = new Vector2f(0f, 0f);
|
||||
public static final Vector2f UNIT_XY = new Vector2f(1f, 1f);
|
||||
|
||||
/**
|
||||
* the x value of the vector.
|
||||
*/
|
||||
public float x;
|
||||
/**
|
||||
* the y value of the vector.
|
||||
*/
|
||||
public float y;
|
||||
|
||||
/**
|
||||
* Creates a Vector2f with the given initial x and y values.
|
||||
*
|
||||
* @param x The x value of this Vector2f.
|
||||
* @param y The y value of this Vector2f.
|
||||
*/
|
||||
public Vector2f(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector2f with x and y set to 0. Equivalent to Vector2f(0,0).
|
||||
*/
|
||||
public Vector2f() {
|
||||
x = y = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Vector2f that contains the passed vector's information
|
||||
*
|
||||
* @param vector2f The vector to copy
|
||||
*/
|
||||
public Vector2f(Vector2f vector2f) {
|
||||
this.x = vector2f.x;
|
||||
this.y = vector2f.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the x and y values of the vector
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector2f set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the x and y values of the vector from another vector
|
||||
*
|
||||
* @param vec the vector to copy from
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector2f set(Vector2f vec) {
|
||||
this.x = vec.x;
|
||||
this.y = vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>add</code> adds a provided vector to this vector creating a
|
||||
* resultant vector which is returned. If the provided vector is null, null
|
||||
* is returned.
|
||||
*
|
||||
* @param vec the vector to add to this.
|
||||
* @return the resultant vector.
|
||||
*/
|
||||
public Vector2f add(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return new Vector2f(x + vec.x, y + vec.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds a provided vector to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls. If the
|
||||
* provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to add to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f addLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds the provided values to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param addX value to add to x
|
||||
* @param addY value to add to y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f addLocal(float addX, float addY) {
|
||||
x += addX;
|
||||
y += addY;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>add</code> adds this vector by <code>vec</code> and stores the
|
||||
* result in <code>result</code>.
|
||||
*
|
||||
* @param vec The vector to add.
|
||||
* @param result The vector to store the result in.
|
||||
* @return The result vector, after adding.
|
||||
*/
|
||||
public Vector2f add(Vector2f vec, Vector2f result) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
if (result == null)
|
||||
result = new Vector2f();
|
||||
result.x = x + vec.x;
|
||||
result.y = y + vec.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>dot</code> calculates the dot product of this vector with a
|
||||
* provided vector. If the provided vector is null, 0 is returned.
|
||||
*
|
||||
* @param vec the vector to dot with this vector.
|
||||
* @return the resultant dot product of this vector and a given vector.
|
||||
*/
|
||||
public float dot(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, 0 returned.");
|
||||
return 0;
|
||||
}
|
||||
return x * vec.x + y * vec.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>cross</code> calculates the cross product of this vector with a
|
||||
* parameter vector v.
|
||||
*
|
||||
* @param v the vector to take the cross product of with this.
|
||||
* @return the cross product vector.
|
||||
*/
|
||||
public Vector3f cross(Vector2f v) {
|
||||
return new Vector3f(0, 0, determinant(v));
|
||||
}
|
||||
|
||||
public float determinant(Vector2f v) {
|
||||
return (x * v.y) - (y * v.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from this to the
|
||||
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
|
||||
*
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
|
||||
* change from this towards finalVec
|
||||
*/
|
||||
public Vector2f interpolate(Vector2f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from beginVec to
|
||||
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
|
||||
*
|
||||
* @param beginVec The begining vector (delta=0)
|
||||
* @param finalVec The final vector to interpolate towards (delta=1)
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from beginVec towards finalVec
|
||||
*/
|
||||
public Vector2f interpolate(
|
||||
Vector2f beginVec,
|
||||
Vector2f finalVec,
|
||||
float changeAmnt
|
||||
) {
|
||||
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a vector... if it is null or its floats are NaN or infinite, return
|
||||
* false. Else return true.
|
||||
*
|
||||
* @param vector the vector to check
|
||||
* @return true or false as stated above.
|
||||
*/
|
||||
public static boolean isValidVector(Vector2f vector) {
|
||||
if (vector == null)
|
||||
return false;
|
||||
if (
|
||||
Float.isNaN(vector.x)
|
||||
||
|
||||
Float.isNaN(vector.y)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
Float.isInfinite(vector.x)
|
||||
||
|
||||
Float.isInfinite(vector.y)
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>length</code> calculates the magnitude of this vector.
|
||||
*
|
||||
* @return the length or magnitude of the vector.
|
||||
*/
|
||||
public float length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>lengthSquared</code> calculates the squared value of the magnitude
|
||||
* of the vector.
|
||||
*
|
||||
* @return the magnitude squared of the vector.
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance squared.
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(Vector2f v) {
|
||||
double dx = x - v.x;
|
||||
double dy = y - v.y;
|
||||
return (float) (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param otherX The X coordinate of the v vector
|
||||
* @param otherY The Y coordinate of the v vector
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(float otherX, float otherY) {
|
||||
double dx = x - otherX;
|
||||
double dy = y - otherY;
|
||||
return (float) (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distance</code> calculates the distance between this vector and
|
||||
* vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance.
|
||||
* @return the distance between the two vectors.
|
||||
*/
|
||||
public float distance(Vector2f v) {
|
||||
return FastMath.sqrt(distanceSquared(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is returned.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return the new vector.
|
||||
*/
|
||||
public Vector2f mult(float scalar) {
|
||||
return new Vector2f(x * scalar, y * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f multLocal(float scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f multLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x *= vec.x;
|
||||
y *= vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this Vector2f's x and y by the scalar and stores the result in
|
||||
* product. The result is returned for chaining. Similar to
|
||||
* product=this*scalar;
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @param product The vector2f to store the result in.
|
||||
* @return product, after multiplication.
|
||||
*/
|
||||
public Vector2f mult(float scalar, Vector2f product) {
|
||||
if (null == product) {
|
||||
product = new Vector2f();
|
||||
}
|
||||
|
||||
product.x = x * scalar;
|
||||
product.y = y * scalar;
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector2f divide(float scalar) {
|
||||
return new Vector2f(x / scalar, y / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f divideLocal(float scalar) {
|
||||
x /= scalar;
|
||||
y /= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>negate</code> returns the negative of this vector. All values are
|
||||
* negated and set to a new vector.
|
||||
*
|
||||
* @return the negated vector.
|
||||
*/
|
||||
public Vector2f negate() {
|
||||
return new Vector2f(-x, -y);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>negateLocal</code> negates the internal values of this vector.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector2f negateLocal() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector creating a new vector object. If the provided vector is
|
||||
* null, an exception is thrown.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector2f subtract(Vector2f vec) {
|
||||
return subtract(vec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector storing the result in the given vector object. If the
|
||||
* provided vector is null, an exception is thrown.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @param store the vector to store the result in. It is safe for this to be
|
||||
* the same as vec. If null, a new vector is created.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector2f subtract(Vector2f vec, Vector2f store) {
|
||||
if (store == null)
|
||||
store = new Vector2f();
|
||||
store.x = x - vec.x;
|
||||
store.y = y - vec.y;
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the given x,y values from those of this
|
||||
* vector creating a new vector object.
|
||||
*
|
||||
* @param valX value to subtract from x
|
||||
* @param valY value to subtract from y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtract(float valX, float valY) {
|
||||
return new Vector2f(x - valX, y - valY);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtractLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts the provided values from this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls.
|
||||
*
|
||||
* @param valX value to subtract from x
|
||||
* @param valY value to subtract from y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtractLocal(float valX, float valY) {
|
||||
x -= valX;
|
||||
y -= valY;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalize</code> returns the unit vector of this vector.
|
||||
*
|
||||
* @return unit vector of this vector.
|
||||
*/
|
||||
public Vector2f normalize() {
|
||||
float length = length();
|
||||
if (length != 0) {
|
||||
return divide(length);
|
||||
}
|
||||
|
||||
return divide(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalizeLocal</code> makes this vector into a unit vector of
|
||||
* itself.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector2f normalizeLocal() {
|
||||
float length = length();
|
||||
if (length != 0) {
|
||||
return divideLocal(length);
|
||||
}
|
||||
|
||||
return divideLocal(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>smallestAngleBetween</code> returns (in radians) the minimum angle
|
||||
* between two vectors. It is assumed that both this vector and the given
|
||||
* vector are unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector a unit vector to find the angle against
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float smallestAngleBetween(Vector2f otherVector) {
|
||||
float dotProduct = dot(otherVector);
|
||||
float angle = FastMath.acos(dotProduct);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>angleBetween</code> returns (in radians) the angle required to
|
||||
* rotate a ray represented by this vector to lie colinear to a ray
|
||||
* described by the given vector. It is assumed that both this vector and
|
||||
* the given vector are unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector the "destination" unit vector
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float angleBetween(Vector2f otherVector) {
|
||||
float angle = FastMath.atan2(otherVector.y, otherVector.x)
|
||||
- FastMath.atan2(y, x);
|
||||
return angle;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector2f setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector2f setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>getAngle</code> returns (in radians) the angle represented by this
|
||||
* Vector2f as expressed by a conversion from rectangular coordinates
|
||||
* (<code>x</code>, <code>y</code>) to polar coordinates
|
||||
* (r, <i>theta</i>).
|
||||
*
|
||||
* @return the angle in radians. [-pi, pi)
|
||||
*/
|
||||
public float getAngle() {
|
||||
return FastMath.atan2(y, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>zero</code> resets this vector's data to zero internally.
|
||||
*/
|
||||
public Vector2f zero() {
|
||||
x = y = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>hashCode</code> returns a unique code for this vector object based
|
||||
* on it's values. If two vectors are logically equivalent, they will return
|
||||
* the same hash code value.
|
||||
*
|
||||
* @return the hash code value of this vector.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 37;
|
||||
hash += 37 * hash + Float.floatToIntBits(x);
|
||||
hash += 37 * hash + Float.floatToIntBits(y);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2f clone() {
|
||||
try {
|
||||
return (Vector2f) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(); // can not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this Vector2f into the given float[] object.
|
||||
*
|
||||
* @param floats The float[] to take this Vector2f. If null, a new float[2]
|
||||
* is created.
|
||||
* @return The array, with X, Y float values in that order
|
||||
*/
|
||||
public float[] toArray(float[] floats) {
|
||||
if (floats == null) {
|
||||
floats = new float[2];
|
||||
}
|
||||
floats[0] = x;
|
||||
floats[1] = y;
|
||||
return floats;
|
||||
}
|
||||
|
||||
/**
|
||||
* are these two vectors the same? they are is they both have the same x and
|
||||
* y values.
|
||||
*
|
||||
* @param o the object to compare for equality
|
||||
* @return true if they are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Vector2f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector2f comp = (Vector2f) o;
|
||||
if (Float.compare(x, comp.x) != 0)
|
||||
return false;
|
||||
if (Float.compare(y, comp.y) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>toString</code> returns the string representation of this vector
|
||||
* object. The format of the string is such: com.jme.math.Vector2f
|
||||
* [X=XX.XXXX, Y=YY.YYYY]
|
||||
*
|
||||
* @return the string representation of this vector.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with serialization. Not to be called manually.
|
||||
*
|
||||
* @param in ObjectInput
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
* @see java.io.Externalizable
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException,
|
||||
ClassNotFoundException {
|
||||
x = in.readFloat();
|
||||
y = in.readFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with serialization. Not to be called manually.
|
||||
*
|
||||
* @param out ObjectOutput
|
||||
* @throws IOException
|
||||
* @see java.io.Externalizable
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeFloat(x);
|
||||
out.writeFloat(y);
|
||||
}
|
||||
|
||||
public void rotateAroundOrigin(float angle, boolean cw) {
|
||||
if (cw)
|
||||
angle = -angle;
|
||||
float newX = FastMath.cos(angle) * x - FastMath.sin(angle) * y;
|
||||
float newY = FastMath.sin(angle) * x + FastMath.cos(angle) * y;
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
}
|
||||
1101
java/com/jme3/math/Vector3f.java
Normal file
1101
java/com/jme3/math/Vector3f.java
Normal file
File diff suppressed because it is too large
Load Diff
971
java/com/jme3/math/Vector4f.java
Normal file
971
java/com/jme3/math/Vector4f.java
Normal file
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* <code>Vector4f</code> defines a Vector for a four float value tuple.
|
||||
* <code>Vector4f</code> can represent any four dimensional value, such as a
|
||||
* vertex, a normal, etc. Utility methods are also included to aid in
|
||||
* mathematical calculations.
|
||||
*
|
||||
* @author Maarten Steur
|
||||
*/
|
||||
public final class Vector4f implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Vector4f.class.getName());
|
||||
|
||||
public final static Vector4f ZERO = new Vector4f(0, 0, 0, 0);
|
||||
public final static Vector4f NAN = new Vector4f(Float.NaN, Float.NaN, Float.NaN, Float.NaN);
|
||||
public final static Vector4f UNIT_X = new Vector4f(1, 0, 0, 0);
|
||||
public final static Vector4f UNIT_Y = new Vector4f(0, 1, 0, 0);
|
||||
public final static Vector4f UNIT_Z = new Vector4f(0, 0, 1, 0);
|
||||
public final static Vector4f UNIT_W = new Vector4f(0, 0, 0, 1);
|
||||
public final static Vector4f UNIT_XYZW = new Vector4f(1, 1, 1, 1);
|
||||
public final static Vector4f POSITIVE_INFINITY = new Vector4f(
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY
|
||||
);
|
||||
public final static Vector4f NEGATIVE_INFINITY = new Vector4f(
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY
|
||||
);
|
||||
|
||||
/**
|
||||
* the x value of the vector.
|
||||
*/
|
||||
public float x;
|
||||
|
||||
/**
|
||||
* the y value of the vector.
|
||||
*/
|
||||
public float y;
|
||||
|
||||
/**
|
||||
* the z value of the vector.
|
||||
*/
|
||||
public float z;
|
||||
|
||||
/**
|
||||
* the w value of the vector.
|
||||
*/
|
||||
public float w;
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector3f</code> with default values
|
||||
* of (0,0,0).
|
||||
*
|
||||
*/
|
||||
public Vector4f() {
|
||||
x = y = z = w = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector4f</code> with provides
|
||||
* values.
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @param z the z value of the vector.
|
||||
* @param w the w value of the vector.
|
||||
*/
|
||||
public Vector4f(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector3f</code> that is a copy of
|
||||
* the provided vector
|
||||
*
|
||||
* @param copy The Vector3f to copy
|
||||
*/
|
||||
public Vector4f(Vector4f copy) {
|
||||
this.set(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the x,y,z,w values of the vector based on passed
|
||||
* parameters.
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @param z the z value of the vector.
|
||||
* @param w the w value of the vector.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector4f set(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the x,y,z values of the vector by copying the
|
||||
* supplied vector.
|
||||
*
|
||||
* @param vect the vector to copy.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector4f set(Vector4f vect) {
|
||||
this.x = vect.x;
|
||||
this.y = vect.y;
|
||||
this.z = vect.z;
|
||||
this.w = vect.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds a provided vector to this vector creating a
|
||||
* resultant vector which is returned. If the provided vector is null, null
|
||||
* is returned.
|
||||
*
|
||||
* @param vec the vector to add to this.
|
||||
* @return the resultant vector.
|
||||
*/
|
||||
public Vector4f add(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return new Vector4f(x + vec.x, y + vec.y, z + vec.z, w + vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds the values of a provided vector storing the values
|
||||
* in the supplied vector.
|
||||
*
|
||||
* @param vec the vector to add to this
|
||||
* @param result the vector to store the result in
|
||||
* @return result returns the supplied result vector.
|
||||
*/
|
||||
public Vector4f add(Vector4f vec, Vector4f result) {
|
||||
result.x = x + vec.x;
|
||||
result.y = y + vec.y;
|
||||
result.z = z + vec.z;
|
||||
result.w = w + vec.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds a provided vector to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls. If the
|
||||
* provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to add to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f addLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
z += vec.z;
|
||||
w += vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds the provided values to this vector, creating a new
|
||||
* vector that is then returned.
|
||||
*
|
||||
* @param addX the x value to add.
|
||||
* @param addY the y value to add.
|
||||
* @param addZ the z value to add.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f add(float addX, float addY, float addZ, float addW) {
|
||||
return new Vector4f(x + addX, y + addY, z + addZ, w + addW);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds the provided values to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param addX value to add to x
|
||||
* @param addY value to add to y
|
||||
* @param addZ value to add to z
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f addLocal(float addX, float addY, float addZ, float addW) {
|
||||
x += addX;
|
||||
y += addY;
|
||||
z += addZ;
|
||||
w += addW;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>scaleAdd</code> multiplies this vector by a scalar then adds the
|
||||
* given Vector3f.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @param add the value to add
|
||||
*/
|
||||
public Vector4f scaleAdd(float scalar, Vector4f add) {
|
||||
x = x * scalar + add.x;
|
||||
y = y * scalar + add.y;
|
||||
z = z * scalar + add.z;
|
||||
w = w * scalar + add.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>scaleAdd</code> multiplies the given vector by a scalar then adds
|
||||
* the given vector.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @param mult the value to multiply the scalar by
|
||||
* @param add the value to add
|
||||
*/
|
||||
public Vector4f scaleAdd(float scalar, Vector4f mult, Vector4f add) {
|
||||
this.x = mult.x * scalar + add.x;
|
||||
this.y = mult.y * scalar + add.y;
|
||||
this.z = mult.z * scalar + add.z;
|
||||
this.w = mult.w * scalar + add.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>dot</code> calculates the dot product of this vector with a
|
||||
* provided vector. If the provided vector is null, 0 is returned.
|
||||
*
|
||||
* @param vec the vector to dot with this vector.
|
||||
* @return the resultant dot product of this vector and a given vector.
|
||||
*/
|
||||
public float dot(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, 0 returned.");
|
||||
return 0;
|
||||
}
|
||||
return x * vec.x + y * vec.y + z * vec.z + w * vec.w;
|
||||
}
|
||||
|
||||
public Vector4f project(Vector4f other) {
|
||||
float n = this.dot(other); // A . B
|
||||
float d = other.lengthSquared(); // |B|^2
|
||||
return new Vector4f(other).normalizeLocal().multLocal(n / d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vector is a unit vector (length() ~= 1), returns
|
||||
* false otherwise.
|
||||
*
|
||||
* @return true if this vector is a unit vector (length() ~= 1), or false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isUnitVector() {
|
||||
float len = length();
|
||||
return 0.99f < len && len < 1.01f;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>length</code> calculates the magnitude of this vector.
|
||||
*
|
||||
* @return the length or magnitude of the vector.
|
||||
*/
|
||||
public float length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>lengthSquared</code> calculates the squared value of the magnitude
|
||||
* of the vector.
|
||||
*
|
||||
* @return the magnitude squared of the vector.
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance squared.
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(Vector4f v) {
|
||||
double dx = x - v.x;
|
||||
double dy = y - v.y;
|
||||
double dz = z - v.z;
|
||||
double dw = w - v.w;
|
||||
return (float) (dx * dx + dy * dy + dz * dz + dw * dw);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distance</code> calculates the distance between this vector and
|
||||
* vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance.
|
||||
* @return the distance between the two vectors.
|
||||
*/
|
||||
public float distance(Vector4f v) {
|
||||
return FastMath.sqrt(distanceSquared(v));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is returned.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return the new vector.
|
||||
*/
|
||||
public Vector4f mult(float scalar) {
|
||||
return new Vector4f(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is supplied as the second parameter and returned.
|
||||
*
|
||||
* @param scalar the scalar to multiply this vector by.
|
||||
* @param product the product to store the result in.
|
||||
* @return product
|
||||
*/
|
||||
public Vector4f mult(float scalar, Vector4f product) {
|
||||
if (null == product) {
|
||||
product = new Vector4f();
|
||||
}
|
||||
|
||||
product.x = x * scalar;
|
||||
product.y = y * scalar;
|
||||
product.z = z * scalar;
|
||||
product.w = w * scalar;
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(float scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
w *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x *= vec.x;
|
||||
y *= vec.y;
|
||||
z *= vec.z;
|
||||
w *= vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by 3 scalars internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param w
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(float x, float y, float z, float w) {
|
||||
this.x *= x;
|
||||
this.y *= y;
|
||||
this.z *= z;
|
||||
this.w *= w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f mult(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return mult(vec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @param store result vector (null to create a new vector)
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f mult(Vector4f vec, Vector4f store) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
if (store == null)
|
||||
store = new Vector4f();
|
||||
return store.set(x * vec.x, y * vec.y, z * vec.z, w * vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector4f divide(float scalar) {
|
||||
scalar = 1f / scalar;
|
||||
return new Vector4f(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f divideLocal(float scalar) {
|
||||
scalar = 1f / scalar;
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
w *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector4f divide(Vector4f scalar) {
|
||||
return new Vector4f(x / scalar.x, y / scalar.y, z / scalar.z, w / scalar.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f divideLocal(Vector4f scalar) {
|
||||
x /= scalar.x;
|
||||
y /= scalar.y;
|
||||
z /= scalar.z;
|
||||
w /= scalar.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>negate</code> returns the negative of this vector. All values are
|
||||
* negated and set to a new vector.
|
||||
*
|
||||
* @return the negated vector.
|
||||
*/
|
||||
public Vector4f negate() {
|
||||
return new Vector4f(-x, -y, -z, -w);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>negateLocal</code> negates the internal values of this vector.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector4f negateLocal() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
w = -w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector creating a new vector object. If the provided vector is
|
||||
* null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f subtract(Vector4f vec) {
|
||||
return new Vector4f(x - vec.x, y - vec.y, z - vec.z, w - vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f subtractLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
z -= vec.z;
|
||||
w -= vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code>
|
||||
*
|
||||
* @param vec the vector to subtract from this
|
||||
* @param result the vector to store the result in
|
||||
* @return result
|
||||
*/
|
||||
public Vector4f subtract(Vector4f vec, Vector4f result) {
|
||||
if (result == null) {
|
||||
result = new Vector4f();
|
||||
}
|
||||
result.x = x - vec.x;
|
||||
result.y = y - vec.y;
|
||||
result.z = z - vec.z;
|
||||
result.w = w - vec.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code> subtracts the provided values from this vector,
|
||||
* creating a new vector that is then returned.
|
||||
*
|
||||
* @param subtractX the x value to subtract.
|
||||
* @param subtractY the y value to subtract.
|
||||
* @param subtractZ the z value to subtract.
|
||||
* @param subtractW the w value to subtract.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f subtract(float subtractX, float subtractY, float subtractZ, float subtractW) {
|
||||
return new Vector4f(x - subtractX, y - subtractY, z - subtractZ, w - subtractW);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts the provided values from this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls.
|
||||
*
|
||||
* @param subtractX the x value to subtract.
|
||||
* @param subtractY the y value to subtract.
|
||||
* @param subtractZ the z value to subtract.
|
||||
* @param subtractW the w value to subtract.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f subtractLocal(
|
||||
float subtractX,
|
||||
float subtractY,
|
||||
float subtractZ,
|
||||
float subtractW
|
||||
) {
|
||||
x -= subtractX;
|
||||
y -= subtractY;
|
||||
z -= subtractZ;
|
||||
w -= subtractW;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalize</code> returns the unit vector of this vector.
|
||||
*
|
||||
* @return unit vector of this vector.
|
||||
*/
|
||||
public Vector4f normalize() {
|
||||
// float length = length();
|
||||
// if (length != 0) {
|
||||
// return divide(length);
|
||||
// }
|
||||
//
|
||||
// return divide(1);
|
||||
float length = x * x + y * y + z * z + w * w;
|
||||
if (length != 1f && length != 0f) {
|
||||
length = 1.0f / FastMath.sqrt(length);
|
||||
return new Vector4f(x * length, y * length, z * length, w * length);
|
||||
}
|
||||
return clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalizeLocal</code> makes this vector into a unit vector of
|
||||
* itself.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector4f normalizeLocal() {
|
||||
// NOTE: this implementation is more optimized
|
||||
// than the old jme normalize as this method
|
||||
// is commonly used.
|
||||
float length = x * x + y * y + z * z + w * w;
|
||||
if (length != 1f && length != 0f) {
|
||||
length = 1.0f / FastMath.sqrt(length);
|
||||
x *= length;
|
||||
y *= length;
|
||||
z *= length;
|
||||
w *= length;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>maxLocal</code> computes the maximum value for each component in
|
||||
* this and <code>other</code> vector. The result is stored in this vector.
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
public Vector4f maxLocal(Vector4f other) {
|
||||
x = other.x > x ? other.x : x;
|
||||
y = other.y > y ? other.y : y;
|
||||
z = other.z > z ? other.z : z;
|
||||
w = other.w > w ? other.w : w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>minLocal</code> computes the minimum value for each component in
|
||||
* this and <code>other</code> vector. The result is stored in this vector.
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
public Vector4f minLocal(Vector4f other) {
|
||||
x = other.x < x ? other.x : x;
|
||||
y = other.y < y ? other.y : y;
|
||||
z = other.z < z ? other.z : z;
|
||||
w = other.w < w ? other.w : w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>zero</code> resets this vector's data to zero internally.
|
||||
*/
|
||||
public Vector4f zero() {
|
||||
x = y = z = w = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>angleBetween</code> returns (in radians) the angle between two
|
||||
* vectors. It is assumed that both this vector and the given vector are
|
||||
* unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector a unit vector to find the angle against
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float angleBetween(Vector4f otherVector) {
|
||||
float dotProduct = dot(otherVector);
|
||||
float angle = FastMath.acos(dotProduct);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from this to the
|
||||
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
|
||||
*
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from this towards finalVec
|
||||
*/
|
||||
public Vector4f interpolate(Vector4f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
|
||||
this.z = (1 - changeAmnt) * this.z + changeAmnt * finalVec.z;
|
||||
this.w = (1 - changeAmnt) * this.w + changeAmnt * finalVec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from beginVec to
|
||||
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
|
||||
*
|
||||
* @param beginVec the beging vector (changeAmnt=0)
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from beginVec towards finalVec
|
||||
*/
|
||||
public Vector4f interpolate(Vector4f beginVec, Vector4f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
|
||||
this.z = (1 - changeAmnt) * beginVec.z + changeAmnt * finalVec.z;
|
||||
this.w = (1 - changeAmnt) * beginVec.w + changeAmnt * finalVec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a vector... if it is null or its floats are NaN or infinite, return
|
||||
* false. Else return true.
|
||||
*
|
||||
* @param vector the vector to check
|
||||
* @return true or false as stated above.
|
||||
*/
|
||||
public static boolean isValidVector(Vector4f vector) {
|
||||
if (vector == null)
|
||||
return false;
|
||||
if (
|
||||
Float.isNaN(vector.x)
|
||||
||
|
||||
Float.isNaN(vector.y)
|
||||
||
|
||||
Float.isNaN(vector.z)
|
||||
||
|
||||
Float.isNaN(vector.w)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
Float.isInfinite(vector.x)
|
||||
||
|
||||
Float.isInfinite(vector.y)
|
||||
||
|
||||
Float.isInfinite(vector.z)
|
||||
||
|
||||
Float.isInfinite(vector.w)
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector4f clone() {
|
||||
try {
|
||||
return (Vector4f) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(); // can not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this Vector3f into the given float[] object.
|
||||
*
|
||||
* @param floats The float[] to take this Vector3f. If null, a new float[3]
|
||||
* is created.
|
||||
* @return The array, with X, Y, Z float values in that order
|
||||
*/
|
||||
public float[] toArray(float[] floats) {
|
||||
if (floats == null) {
|
||||
floats = new float[4];
|
||||
}
|
||||
floats[0] = x;
|
||||
floats[1] = y;
|
||||
floats[2] = z;
|
||||
floats[3] = w;
|
||||
return floats;
|
||||
}
|
||||
|
||||
/**
|
||||
* are these two vectors the same? they are is they both have the same x,y,
|
||||
* and z values.
|
||||
*
|
||||
* @param o the object to compare for equality
|
||||
* @return true if they are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Vector4f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector4f comp = (Vector4f) o;
|
||||
if (Float.compare(x, comp.x) != 0)
|
||||
return false;
|
||||
if (Float.compare(y, comp.y) != 0)
|
||||
return false;
|
||||
if (Float.compare(z, comp.z) != 0)
|
||||
return false;
|
||||
if (Float.compare(w, comp.w) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>hashCode</code> returns a unique code for this vector object based
|
||||
* on it's values. If two vectors are logically equivalent, they will return
|
||||
* the same hash code value.
|
||||
*
|
||||
* @return the hash code value of this vector.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 37;
|
||||
hash += 37 * hash + Float.floatToIntBits(x);
|
||||
hash += 37 * hash + Float.floatToIntBits(y);
|
||||
hash += 37 * hash + Float.floatToIntBits(z);
|
||||
hash += 37 * hash + Float.floatToIntBits(w);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>toString</code> returns the string representation of this vector.
|
||||
* The format is:
|
||||
*
|
||||
* org.jme.math.Vector3f [X=XX.XXXX, Y=YY.YYYY, Z=ZZ.ZZZZ, W=WW.WWWW]
|
||||
*
|
||||
* @return the string representation of this vector.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ", " + z + ", " + w + ")";
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector4f setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector4f setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector4f setZ(float z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
public Vector4f setW(float w) {
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return x value if index == 0, y value if index == 1 or z value if index
|
||||
* == 2
|
||||
* @throws IllegalArgumentException if index is not one of 0, 1, 2.
|
||||
*/
|
||||
public float get(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
case 3:
|
||||
return w;
|
||||
}
|
||||
throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index which field index in this vector to set.
|
||||
* @param value to set to one of x, y, z or w.
|
||||
* @throws IllegalArgumentException if index is not one of 0, 1, 2, 3.
|
||||
*/
|
||||
public void set(int index, float value) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
case 2:
|
||||
z = value;
|
||||
return;
|
||||
case 3:
|
||||
w = value;
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
|
||||
}
|
||||
|
||||
}
|
||||
105
java/com/jme3/system/NanoTimer.java
Normal file
105
java/com/jme3/system/NanoTimer.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.system;
|
||||
|
||||
/**
|
||||
* <code>NanoTimer</code> is a System.nanoTime implementation of
|
||||
* <code>Timer</code>. This is primarily useful for headless applications
|
||||
* running on a server.
|
||||
*
|
||||
* @author Matthew D. Hicks
|
||||
*/
|
||||
public class NanoTimer extends Timer {
|
||||
|
||||
private static final long TIMER_RESOLUTION = 1000000000L;
|
||||
private static final float INVERSE_TIMER_RESOLUTION = 1f / TIMER_RESOLUTION;
|
||||
|
||||
private long startTime;
|
||||
private long previousTime;
|
||||
private float tpf;
|
||||
private float fps;
|
||||
private long currentTime;
|
||||
|
||||
public NanoTimer() {
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in seconds. The timer starts at 0.0 seconds.
|
||||
*
|
||||
* @return the current time in seconds
|
||||
*/
|
||||
|
||||
protected long getTimeInternal() {
|
||||
return System.nanoTime() - startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTimeInSeconds() {
|
||||
return getTime() * INVERSE_TIMER_RESOLUTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getResolution() {
|
||||
return TIMER_RESOLUTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFrameRate() {
|
||||
return fps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTimePerFrame() {
|
||||
return tpf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
currentTime = getTimeInternal();
|
||||
tpf = (currentTime - previousTime) * (1.0f / TIMER_RESOLUTION);
|
||||
fps = 1.0f / tpf;
|
||||
previousTime = getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
startTime = System.nanoTime();
|
||||
currentTime = getTimeInternal();
|
||||
previousTime = getTime();
|
||||
}
|
||||
}
|
||||
93
java/com/jme3/system/Timer.java
Normal file
93
java/com/jme3/system/Timer.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.system;
|
||||
|
||||
/**
|
||||
* <code>Timer</code> is the base class for a high resolution timer. It is
|
||||
* created from getTimer("display system")
|
||||
*
|
||||
* @author Mark Powell
|
||||
* @version $Id: Timer.java,v 1.18 2007/03/09 10:19:34 rherlitz Exp $
|
||||
*/
|
||||
public abstract class Timer {
|
||||
|
||||
/**
|
||||
* Returns the current time in ticks. A tick is an arbitrary measure of time
|
||||
* defined by the timer implementation. The number of ticks per second is
|
||||
* given by <code>getResolution()</code>. The timer starts at 0 ticks.
|
||||
*
|
||||
* @return a long value representing the current time
|
||||
*/
|
||||
public abstract long getTime();
|
||||
|
||||
/**
|
||||
* Returns the time in seconds. The timer starts at 0.0 seconds.
|
||||
*
|
||||
* @return the current time in seconds
|
||||
*/
|
||||
public float getTimeInSeconds() {
|
||||
return getTime() / (float) getResolution();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolution of the timer.
|
||||
*
|
||||
* @return the number of timer ticks per second
|
||||
*/
|
||||
public abstract long getResolution();
|
||||
|
||||
/**
|
||||
* Returns the "calls per second". If this is called every frame, then it
|
||||
* will return the "frames per second".
|
||||
*
|
||||
* @return The "calls per second".
|
||||
*/
|
||||
public abstract float getFrameRate();
|
||||
|
||||
/**
|
||||
* Returns the time, in seconds, between the last call and the current one.
|
||||
*
|
||||
* @return Time between this call and the last one.
|
||||
*/
|
||||
public abstract float getTimePerFrame();
|
||||
|
||||
/**
|
||||
* <code>update</code> recalculates the frame rate based on the previous
|
||||
* call to update. It is assumed that update is called each frame.
|
||||
*/
|
||||
public abstract void update();
|
||||
|
||||
/**
|
||||
* Reset the timer to 0. Clear any tpf history.
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
||||
178
java/com/jme3/util/TempVars.java
Normal file
178
java/com/jme3/util/TempVars.java
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.util;
|
||||
|
||||
import com.jme3.math.*;
|
||||
|
||||
|
||||
/**
|
||||
* Temporary variables assigned to each thread. Engine classes may access these
|
||||
* temp variables with TempVars.get(), all retrieved TempVars instances must be
|
||||
* returned via TempVars.release(). This returns an available instance of the
|
||||
* TempVar class ensuring this particular instance is never used elsewhere in
|
||||
* the mean time.
|
||||
*/
|
||||
public class TempVars {
|
||||
|
||||
/**
|
||||
* Allow X instances of TempVars in a single thread.
|
||||
*/
|
||||
private static final int STACK_SIZE = 5;
|
||||
|
||||
/**
|
||||
* <code>TempVarsStack</code> contains a stack of TempVars. Every time
|
||||
* TempVars.get() is called, a new entry is added to the stack, and the
|
||||
* index incremented. When TempVars.release() is called, the entry is
|
||||
* checked against the current instance and then the index is decremented.
|
||||
*/
|
||||
private static class TempVarsStack {
|
||||
|
||||
int index = 0;
|
||||
TempVars[] tempVars = new TempVars[STACK_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* ThreadLocal to store a TempVarsStack for each thread. This ensures each
|
||||
* thread has a single TempVarsStack that is used only in method calls in
|
||||
* that thread.
|
||||
*/
|
||||
private static final ThreadLocal<TempVarsStack> varsLocal = new ThreadLocal<TempVarsStack>() {
|
||||
|
||||
@Override
|
||||
public TempVarsStack initialValue() {
|
||||
return new TempVarsStack();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This instance of TempVars has been retrieved but not released yet.
|
||||
*/
|
||||
private boolean isUsed = false;
|
||||
|
||||
private TempVars() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire an instance of the TempVar class. You have to release the
|
||||
* instance after use by calling the release() method. If more than
|
||||
* STACK_SIZE (currently 5) instances are requested in a single thread then
|
||||
* an ArrayIndexOutOfBoundsException will be thrown.
|
||||
*
|
||||
* @return A TempVar instance
|
||||
*/
|
||||
public static TempVars get() {
|
||||
TempVarsStack stack = varsLocal.get();
|
||||
|
||||
TempVars instance = stack.tempVars[stack.index];
|
||||
|
||||
if (instance == null) {
|
||||
// Create new
|
||||
instance = new TempVars();
|
||||
|
||||
// Put it in there
|
||||
stack.tempVars[stack.index] = instance;
|
||||
}
|
||||
|
||||
stack.index++;
|
||||
|
||||
instance.isUsed = true;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases this instance of TempVars. Once released, the contents of the
|
||||
* TempVars are undefined. The TempVars must be released in the opposite
|
||||
* order that they are retrieved, e.g. Acquiring vars1, then acquiring
|
||||
* vars2, vars2 MUST be released first otherwise an exception will be
|
||||
* thrown.
|
||||
*/
|
||||
public void release() {
|
||||
if (!isUsed) {
|
||||
throw new IllegalStateException("This instance of TempVars was already released!");
|
||||
}
|
||||
|
||||
isUsed = false;
|
||||
|
||||
TempVarsStack stack = varsLocal.get();
|
||||
|
||||
// Return it to the stack
|
||||
stack.index--;
|
||||
|
||||
// Check if it is actually there
|
||||
if (stack.tempVars[stack.index] != this) {
|
||||
throw new IllegalStateException(
|
||||
"An instance of TempVars has not been released in a called method!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Color
|
||||
*/
|
||||
public final ColorRGBA color = new ColorRGBA();
|
||||
/**
|
||||
* General vectors.
|
||||
*/
|
||||
public final Vector3f vect1 = new Vector3f();
|
||||
public final Vector3f vect2 = new Vector3f();
|
||||
public final Vector3f vect3 = new Vector3f();
|
||||
public final Vector3f vect4 = new Vector3f();
|
||||
public final Vector3f vect5 = new Vector3f();
|
||||
public final Vector3f vect6 = new Vector3f();
|
||||
public final Vector3f vect7 = new Vector3f();
|
||||
// seems the maximum number of vector used is 7 in com.jme3.bounding.java
|
||||
public final Vector3f vect8 = new Vector3f();
|
||||
public final Vector3f vect9 = new Vector3f();
|
||||
public final Vector3f vect10 = new Vector3f();
|
||||
public final Vector4f vect4f = new Vector4f();
|
||||
public final Vector3f[] tri = { new Vector3f(),
|
||||
new Vector3f(),
|
||||
new Vector3f() };
|
||||
/**
|
||||
* 2D vector
|
||||
*/
|
||||
public final Vector2f vect2d = new Vector2f();
|
||||
public final Vector2f vect2d2 = new Vector2f();
|
||||
/**
|
||||
* General matrices.
|
||||
*/
|
||||
public final Matrix3f tempMat3 = new Matrix3f();
|
||||
public final Matrix4f tempMat4 = new Matrix4f();
|
||||
public final Matrix4f tempMat42 = new Matrix4f();
|
||||
/**
|
||||
* General quaternions.
|
||||
*/
|
||||
public final Quaternion quat1 = new Quaternion();
|
||||
public final Quaternion quat2 = new Quaternion();
|
||||
|
||||
public final float[] matrixWrite = new float[16];
|
||||
}
|
||||
672
java/io/eiren/math/FloatMath.java
Normal file
672
java/io/eiren/math/FloatMath.java
Normal file
@@ -0,0 +1,672 @@
|
||||
package io.eiren.math;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.math.Vector4f;
|
||||
|
||||
|
||||
public class FloatMath {
|
||||
|
||||
public static final float PI = (float) Math.PI;
|
||||
public static final float TWO_PI = (float) (Math.PI * 2);
|
||||
public static final float ANGLE_EPSILON = 0.028f; // in degrees (float
|
||||
// epsilon for sin/cos)
|
||||
public static final float ANGLE_EPSILON_RAD = toRad(ANGLE_EPSILON);
|
||||
|
||||
public static final float ZERO_TOLERANCE_F = FastMath.ZERO_TOLERANCE;
|
||||
public static final double ZERO_TOLERANCE_D = 0.0001d;
|
||||
|
||||
public static final float SQRT_TWO = (float) Math.sqrt(2f);
|
||||
public static final float INV_SQRT_TWO = 1f / SQRT_TWO;
|
||||
public static final float SQRT_THREE = (float) Math.sqrt(3f);
|
||||
public static final float INV_SQRT_THREE = 1f / SQRT_THREE;
|
||||
public static final float TWO_FPI = PI * 2;
|
||||
|
||||
public static final float SIN_75_DEG = 0.965926f;
|
||||
public static final float SIN_60_DEG = 0.866025f;
|
||||
public static final float SIN_45_DEG = 0.707107f;
|
||||
public static final float SIN_30_DEG = 0.5f;
|
||||
public static final float SIN_15_DEG = 0.258819f;
|
||||
|
||||
public static final float COS_75_DEG = 0.258819f;
|
||||
public static final float COS_60_DEG = 0.5f;
|
||||
public static final float COS_45_DEG = 0.707107f;
|
||||
public static final float COS_30_DEG = 0.866025f;
|
||||
public static final float COS_15_DEG = 0.965926f;
|
||||
|
||||
public static final int TEN_BITS = ~(~0 << 10);
|
||||
public static final int TENTH_BIT = 1 << 10;
|
||||
public static final int TEN_BITS_MAX = ~(~0 << 9);
|
||||
public static final int TEN_BITS_MAX_UNSIGNED = ~(~0 << 10);
|
||||
public static final int TWO_BITS = ~(~0 << 2);
|
||||
public static final int SECOND_BIT = 1 << 2;
|
||||
public static final int TWO_BITS_MAX = ~(~0 << 1);
|
||||
public static final int TWO_BITS_MAX_UNSIGNED = ~(~0 << 2);
|
||||
|
||||
public static float roundIfZero(float x) {
|
||||
return Math.abs(x) < ZERO_TOLERANCE_F ? 0.0f : x;
|
||||
}
|
||||
|
||||
public static boolean equalsToZero(float x) {
|
||||
return Math.abs(x) < ZERO_TOLERANCE_F;
|
||||
}
|
||||
|
||||
public static boolean lessThanZero(float x) {
|
||||
return (x < -ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean lessOrEqualsToZero(float x) {
|
||||
return (x < ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean greaterThanZero(float x) {
|
||||
return (x > ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean greaterOrEqualsToZero(float x) {
|
||||
return (x > -ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean equalsToZero(float x, float epsilon) {
|
||||
return Math.abs(x) < epsilon;
|
||||
}
|
||||
|
||||
public static boolean equalsWithEpsilon(float x, float y) {
|
||||
return Math.abs(x - y) < ZERO_TOLERANCE_F;
|
||||
}
|
||||
|
||||
public static boolean equalsWithEpsilon(float x, float y, float epsilon) {
|
||||
return Math.abs(x - y) < epsilon;
|
||||
}
|
||||
|
||||
public static boolean lessWithEpsilon(float x, float y) {
|
||||
return (x < y - ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean lessOrEqualsWithEpsilon(float x, float y) {
|
||||
return (x < y + ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean lessWithEpsilon(float x, float y, float epsilon) {
|
||||
return (x < y - epsilon);
|
||||
}
|
||||
|
||||
public static boolean lessOrEqualsWithEpsilon(float x, float y, float epsilon) {
|
||||
return (x < y + epsilon);
|
||||
}
|
||||
|
||||
public static boolean greaterWithEpsilon(float x, float y) {
|
||||
return (x > y + ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean greaterOrEqualsWithEpsilon(float x, float y) {
|
||||
return (x > y - ZERO_TOLERANCE_F);
|
||||
}
|
||||
|
||||
public static boolean greaterWithEpsilon(float x, float y, float epsilon) {
|
||||
return (x > y + epsilon);
|
||||
}
|
||||
|
||||
public static boolean greaterOrEqualsWithEpsilon(float x, float y, float epsilon) {
|
||||
return (x > y - epsilon);
|
||||
}
|
||||
|
||||
public static double roundIfZero(double x) {
|
||||
return Math.abs(x) < ZERO_TOLERANCE_D ? 0.0d : x;
|
||||
}
|
||||
|
||||
public static boolean equalsToZero(double x) {
|
||||
return Math.abs(x) < ZERO_TOLERANCE_D;
|
||||
}
|
||||
|
||||
public static boolean equalsWithEpsilon(double x, double y) {
|
||||
return Math.abs(x - y) < ZERO_TOLERANCE_D;
|
||||
}
|
||||
|
||||
public static boolean lessWithEpsilon(double x, double y) {
|
||||
return (x < y - ZERO_TOLERANCE_D);
|
||||
}
|
||||
|
||||
public static boolean lessOrEqualsWithEpsilon(double x, double y) {
|
||||
return (x < y + ZERO_TOLERANCE_D);
|
||||
}
|
||||
|
||||
public static boolean greaterWithEpsilon(double x, double y) {
|
||||
return (x > y + ZERO_TOLERANCE_D);
|
||||
}
|
||||
|
||||
public static boolean greaterOrEqualsWithEpsilon(double x, double y) {
|
||||
return (x > y - ZERO_TOLERANCE_D);
|
||||
}
|
||||
|
||||
public static float toDegrees(float angrad) {
|
||||
return angrad * 180.0f / PI;
|
||||
}
|
||||
|
||||
public static float toRad(float deg) {
|
||||
return deg / 180.0f * PI;
|
||||
}
|
||||
|
||||
public static boolean radEqual(float angle1, float angle2) {
|
||||
float diff = clampRad(angle1 - angle2);
|
||||
return Math.abs(diff) < ANGLE_EPSILON_RAD;
|
||||
}
|
||||
|
||||
public static boolean degreesEqual(float angle1, float angle2) {
|
||||
float diff = clampDegrees(angle1 - angle2);
|
||||
return Math.abs(diff) < ANGLE_EPSILON;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #normalizeRad(float)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static float clampRad(float angle) {
|
||||
return normalizeRad(angle);
|
||||
}
|
||||
|
||||
public static float normalizeRad(float angle) {
|
||||
return FastMath.normalize(angle, -FastMath.PI, FastMath.PI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #normalizeDegrees(float)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static float clampDegrees(float angle) {
|
||||
return normalizeDegrees(angle);
|
||||
}
|
||||
|
||||
public static float normalizeDegrees(float angle) {
|
||||
return FastMath.normalize(angle, -180f, 180f);
|
||||
}
|
||||
|
||||
public static float animateEase(float t) {
|
||||
// Special case of Bezier interpolation (p0 = p1 = 0, p2 = p3 = 1)
|
||||
return (3.0f - 2.0f * t) * t * t;
|
||||
}
|
||||
|
||||
public static float animateEaseIn(float t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lineary remaps value from the source interval to the target interval.
|
||||
* <a href="https://en.wikipedia.org/wiki/Linear_interpolation">details</a>
|
||||
*/
|
||||
public static float mapValue(
|
||||
float value,
|
||||
float sourceStart,
|
||||
float sourceEnd,
|
||||
float targetStart,
|
||||
float targetEnd
|
||||
) {
|
||||
return targetStart
|
||||
+ (value - sourceStart) * (targetEnd - targetStart) / (sourceEnd - sourceStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the given value and remaps to the target interval.
|
||||
* <p>
|
||||
* Note the source interval values should be sorted.
|
||||
*/
|
||||
public static float mapValueWithClampBefore(
|
||||
float value,
|
||||
float sourceBottom,
|
||||
float sourceTop,
|
||||
float targetBottom,
|
||||
float targetTop
|
||||
) {
|
||||
return mapValue(
|
||||
clamp(value, sourceBottom, sourceTop),
|
||||
sourceBottom,
|
||||
sourceTop,
|
||||
targetBottom,
|
||||
targetTop
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps the given value to the target interval and clamps.
|
||||
* <p>
|
||||
* Note the target interval values should be sorted.
|
||||
*/
|
||||
public static float mapValueWithClampAfter(
|
||||
float value,
|
||||
float sourceBottom,
|
||||
float sourceTop,
|
||||
float targetBottom,
|
||||
float targetTop
|
||||
) {
|
||||
return clamp(
|
||||
mapValue(value, sourceBottom, sourceTop, targetBottom, targetTop),
|
||||
targetBottom,
|
||||
targetTop
|
||||
);
|
||||
}
|
||||
|
||||
public static float smoothstep(float edge0, float edge1, float x) {
|
||||
// Scale, bias and saturate x to 0..1 range
|
||||
x = FastMath.clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
|
||||
// Evaluate polynomial
|
||||
return x * x * (3f - 2f * x);
|
||||
}
|
||||
|
||||
public static float smootherstep(float edge0, float edge1, float x) {
|
||||
// Scale, and clamp x to 0..1 range
|
||||
x = FastMath.clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
|
||||
// Evaluate polynomial
|
||||
return x * x * x * (x * (x * 6f - 15f) + 10f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies linear contrast (with clamping).
|
||||
*
|
||||
* @param t - input value in range (0..1)
|
||||
* @param k - contrast factor in range (-1..1):
|
||||
* <ul>
|
||||
* <li>1.0 - maximal contrast</li>
|
||||
* <li><b>0.0</b> - bypass (returns input value)</li>
|
||||
* <li>-1.0 - minimal contrast (returns 0.5f for any input)</li>
|
||||
* </ul>
|
||||
* @return contrasted value in range (0..1)
|
||||
*/
|
||||
public static float contrastLinear(float t, float k) {
|
||||
float x = 2f * t - 1f; // -1..1
|
||||
float gamma = (1f + k) / (1f - k);
|
||||
float f = FastMath.clamp(gamma * x, -1f, 1f); // -1..1
|
||||
return 0.5f * (f + 1f); // 0..1
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies non-linear contrast by power function.
|
||||
*
|
||||
* @param t - input value in range (0..1)
|
||||
* @param k - contrast factor in range (-1..1) exclusive:
|
||||
* <ul>
|
||||
* <li>0.999 - maximal contrast</li>
|
||||
* <li>0.0 - bypass (returns input value)</li>
|
||||
* <li>-0.999 - minimal contrast</li>
|
||||
* </ul>
|
||||
* @return contrasted value in range (0..1)
|
||||
*/
|
||||
public static float contrastPower(float t, float k) {
|
||||
float x = 2f * t - 1f; // -1..1
|
||||
float gamma = (1f - k) / (1f + k);
|
||||
float f = FastMath.sign(x) * FastMath.pow(FastMath.abs(x), gamma); // -1..1
|
||||
return 0.5f * (f + 1f); // 0..1
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies non-linear contrast by square splines.
|
||||
*
|
||||
* @param t - input value in range (0..1)
|
||||
* @param k - contrast factor in range (-1..1):
|
||||
* <ul>
|
||||
* <li>1.0 - maximal contrast</li>
|
||||
* <li>0.0 - bypass (returns input value)</li>
|
||||
* <li>-1.0 - minimal contrast</li>
|
||||
* </ul>
|
||||
* @return contrasted value in range (0..1)
|
||||
*/
|
||||
public static float contrastQuadricSpline(float t, float k) {
|
||||
float x = 2f * t - 1f; // -1..1
|
||||
float f = x * (1f + k * (1f - FastMath.abs(x))); // -1..1
|
||||
return 0.5f * (f + 1f); // 0..1
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies non-linear contrast by square splines inverted function.
|
||||
*
|
||||
* @param t - input value in range (0..1)
|
||||
* @param k - contrast factor in range (-2..2):
|
||||
* <ul>
|
||||
* <li>2.0 - maximal contrast</li>
|
||||
* <li>0.0 - bypass (returns input value)</li>
|
||||
* <li>-2.0 - minimal contrast</li>
|
||||
* </ul>
|
||||
* @return contrasted value in range (0..1)
|
||||
*/
|
||||
public static float contrastInvertQuadricSpline(float t, float k) {
|
||||
float x = 2f * t - 1f; // -1..1
|
||||
float g;
|
||||
if (k > 0) {
|
||||
g = FastMath.sign(x) * FastMath.sqrt(FastMath.abs(x)) - 2f * x;
|
||||
} else {
|
||||
g = FastMath.sign(x) * (FastMath.sqrt(1f - FastMath.abs(x)) - 1f);
|
||||
}
|
||||
float f = (1f + k) * x + k * g; // -1..1
|
||||
return 0.5f * (f + 1f); // 0..1
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies non-linear contrast by cubic splines.
|
||||
*
|
||||
* @param t - input value in range (0..1)
|
||||
* @param k - contrast factor in range (-1..1):
|
||||
* <ul>
|
||||
* <li>1.0 - maximal contrast</li>
|
||||
* <li>0.0 - bypass (returns input value)</li>
|
||||
* <li>-1.0 - minimal contrast</li>
|
||||
* </ul>
|
||||
* @return contrasted value in range (0..1)
|
||||
*/
|
||||
public static float contrastCubicSpline(float t, float k) {
|
||||
float x = 2f * t - 1f; // -1..1
|
||||
float f = x * (1f + FastMath.abs(k) * (x * x - 1f));
|
||||
if (k < 0)
|
||||
f -= x * 3f * k * (1f - FastMath.abs(x));
|
||||
return 0.5f * (f + 1f); // 0..1
|
||||
}
|
||||
|
||||
public static float fraction(float f) {
|
||||
return f - (int) f;
|
||||
}
|
||||
|
||||
public static double fraction(double d) {
|
||||
return d - (long) d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not copy {@link Math} methods.
|
||||
*/
|
||||
@Deprecated
|
||||
public static float min(float a, float b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
public static float min(float a, float b, float c) {
|
||||
return Math.min(Math.min(a, b), c);
|
||||
}
|
||||
|
||||
public static float min(float a, float b, float c, float d) {
|
||||
return Math.min(Math.min(a, b), Math.min(c, d));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not copy {@link Math} methods.
|
||||
*/
|
||||
@Deprecated
|
||||
public static float max(float a, float b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
public static float max(float a, float b, float c) {
|
||||
return Math.max(Math.max(a, b), c);
|
||||
}
|
||||
|
||||
public static float max(float a, float b, float c, float d) {
|
||||
return Math.max(Math.max(a, b), Math.max(c, d));
|
||||
}
|
||||
|
||||
public static float cos(float value) {
|
||||
return (float) Math.cos(value);
|
||||
}
|
||||
|
||||
public static float sin(float value) {
|
||||
return (float) Math.sin(value);
|
||||
}
|
||||
|
||||
public static float ceil(float value) {
|
||||
return (float) Math.ceil(value);
|
||||
}
|
||||
|
||||
public static float floor(float value) {
|
||||
return (float) Math.floor(value);
|
||||
}
|
||||
|
||||
public static float pow(float value, float power) {
|
||||
return (float) Math.pow(value, power);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not copy {@link Math} methods.
|
||||
*/
|
||||
@Deprecated
|
||||
public static float abs(float value) {
|
||||
return (float) Math.abs(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not copy {@link Math} methods.
|
||||
*/
|
||||
@Deprecated
|
||||
public static float round(float value) {
|
||||
return (float) Math.round(value);
|
||||
}
|
||||
|
||||
public static float sqrt(float value) {
|
||||
return (float) Math.sqrt(value);
|
||||
}
|
||||
|
||||
public static float distance(float x0, float y0, float z0, float x1, float y1, float z1) {
|
||||
return distance(x1 - x0, y1 - y0, z1 - z0);
|
||||
}
|
||||
|
||||
public static float distance(float x, float y, float z) {
|
||||
return sqrt(sqrDistance(x, y, z));
|
||||
}
|
||||
|
||||
public static float sqrDistance(float x, float y, float z) {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
public static float distance(float x, float y) {
|
||||
return sqrt(sqrDistance(x, y));
|
||||
}
|
||||
|
||||
public static float sqrDistance(float x, float y) {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
public static float sqrDistance(Vector3f v, float x1, float y1, float z1) {
|
||||
return sqrDistance(x1 - v.x, y1 - v.y, z1 - v.z);
|
||||
}
|
||||
|
||||
public static float sqrDistance(float x0, float y0, float z0, float x1, float y1, float z1) {
|
||||
return sqrDistance(x1 - x0, y1 - y0, z1 - z0);
|
||||
}
|
||||
|
||||
public static float hypot(float x, float y) {
|
||||
return FastMath.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
public static float hypot(float x, float y, float z) {
|
||||
return FastMath.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as FastMath.clamp
|
||||
*/
|
||||
public static float clamp(float value, float min, float max) {
|
||||
if (value <= min)
|
||||
return min;
|
||||
if (value >= max)
|
||||
return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Vector3f int2101010RevToFloats(int packedValue, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
store.x = packedValue & TEN_BITS_MAX;
|
||||
if ((packedValue & TENTH_BIT) != 0)
|
||||
store.x *= -1;
|
||||
store.y = (packedValue >>> 10) & TEN_BITS_MAX;
|
||||
if ((packedValue & (TENTH_BIT << 10)) != 0)
|
||||
store.y *= -1;
|
||||
store.z = (packedValue >>> 20) & TEN_BITS_MAX;
|
||||
if ((packedValue & (TENTH_BIT << 20)) != 0)
|
||||
store.z *= -1;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToInt210101Rev(Vector3f values) {
|
||||
int store = 0;
|
||||
store |= ((int) values.x) & TEN_BITS_MAX;
|
||||
if (values.x < 0)
|
||||
store |= TENTH_BIT;
|
||||
store |= (((int) values.y) & TEN_BITS_MAX) << 10;
|
||||
if (values.y < 0)
|
||||
store |= TENTH_BIT << 10;
|
||||
store |= (((int) values.z) & TEN_BITS_MAX) << 20;
|
||||
if (values.z < 0)
|
||||
store |= TENTH_BIT << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToInt210101RevNormalized(Vector3f values) {
|
||||
int store = 0;
|
||||
store |= ((int) (values.x * TEN_BITS)) & TEN_BITS_MAX;
|
||||
if (values.x < 0)
|
||||
store |= TENTH_BIT;
|
||||
store |= (((int) (values.y * TEN_BITS)) & TEN_BITS_MAX) << 10;
|
||||
if (values.y < 0)
|
||||
store |= TENTH_BIT << 10;
|
||||
store |= (((int) (values.z * TEN_BITS)) & TEN_BITS_MAX) << 20;
|
||||
if (values.z < 0)
|
||||
store |= TENTH_BIT << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToUnsignedInt210101Rev(Vector3f values) {
|
||||
int store = 0;
|
||||
store |= ((int) values.x) & TEN_BITS;
|
||||
store |= (((int) values.y) & TEN_BITS) << 10;
|
||||
store |= (((int) values.z) & TEN_BITS) << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToUnsignedInt210101RevNormalized(Vector3f values) {
|
||||
int store = 0;
|
||||
store |= ((int) (values.x * TEN_BITS)) & TEN_BITS;
|
||||
store |= (((int) (values.y * TEN_BITS)) & TEN_BITS) << 10;
|
||||
store |= (((int) (values.z * TEN_BITS)) & TEN_BITS) << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToInt210101Rev(float x, float y, float z) {
|
||||
int store = 0;
|
||||
store |= ((int) x) & TEN_BITS_MAX;
|
||||
if (x < 0)
|
||||
store |= TENTH_BIT;
|
||||
store |= (((int) y) & TEN_BITS_MAX) << 10;
|
||||
if (y < 0)
|
||||
store |= TENTH_BIT << 10;
|
||||
store |= (((int) z) & TEN_BITS_MAX) << 20;
|
||||
if (z < 0)
|
||||
store |= TENTH_BIT << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToUnsignedInt210101Rev(float x, float y, float z) {
|
||||
int store = 0;
|
||||
store |= ((int) x) & TEN_BITS;
|
||||
store |= (((int) y) & TEN_BITS) << 10;
|
||||
store |= (((int) z) & TEN_BITS) << 20;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector4f int2101010RevToFloats(int packedValue, Vector4f store) {
|
||||
if (store == null)
|
||||
store = new Vector4f();
|
||||
store.x = packedValue & TEN_BITS_MAX;
|
||||
if ((packedValue & TENTH_BIT) != 0)
|
||||
store.x *= -1;
|
||||
store.y = (packedValue >>> 10) & TEN_BITS_MAX;
|
||||
if ((packedValue & (TENTH_BIT << 10)) != 0)
|
||||
store.y *= -1;
|
||||
store.z = (packedValue >>> 20) & TEN_BITS_MAX;
|
||||
if ((packedValue & (TENTH_BIT << 20)) != 0)
|
||||
store.z *= -1;
|
||||
store.w = (packedValue >>> 30) & TWO_BITS_MAX;
|
||||
if ((packedValue & (SECOND_BIT << 30)) != 0)
|
||||
store.w *= -1;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToInt210101Rev(Vector4f values) {
|
||||
int store = 0;
|
||||
store |= ((int) values.x) & TEN_BITS_MAX;
|
||||
if (values.x < 0)
|
||||
store |= TENTH_BIT;
|
||||
store |= (((int) values.y) & TEN_BITS_MAX) << 10;
|
||||
if (values.y < 0)
|
||||
store |= TENTH_BIT << 10;
|
||||
store |= (((int) values.z) & TEN_BITS_MAX) << 20;
|
||||
if (values.z < 0)
|
||||
store |= TENTH_BIT << 20;
|
||||
store |= (((int) values.z) & TWO_BITS_MAX) << 30;
|
||||
if (values.w < 0)
|
||||
store |= SECOND_BIT << 30;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static int floatToUnsignedInt210101Rev(Vector4f values) {
|
||||
int store = 0;
|
||||
store |= ((int) values.x) & TEN_BITS;
|
||||
store |= (((int) values.y) & TEN_BITS) << 10;
|
||||
store |= (((int) values.z) & TEN_BITS) << 20;
|
||||
store |= (((int) values.z) & TWO_BITS) << 30;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector3f unsignedInt2101010RevToFloats(int packedValue, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
store.x = packedValue & TEN_BITS;
|
||||
store.y = (packedValue >>> 10) & TEN_BITS;
|
||||
store.z = (packedValue >>> 20) & TEN_BITS;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector4f unsignedInt2101010RevToFloats(int packedValue, Vector4f store) {
|
||||
if (store == null)
|
||||
store = new Vector4f();
|
||||
store.x = packedValue & TEN_BITS;
|
||||
store.y = (packedValue >>> 10) & TEN_BITS;
|
||||
store.z = (packedValue >>> 20) & TEN_BITS;
|
||||
store.w = (packedValue >>> 30) & TWO_BITS;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector3f int2101010RevNormalizedToFloats(int packedValue, Vector3f store) {
|
||||
store = int2101010RevToFloats(packedValue, store);
|
||||
store.x /= TEN_BITS_MAX;
|
||||
store.y /= TEN_BITS_MAX;
|
||||
store.z /= TEN_BITS_MAX;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector4f int2101010RevNormalizedToFloats(int packedValue, Vector4f store) {
|
||||
store = int2101010RevToFloats(packedValue, store);
|
||||
store.x /= TEN_BITS_MAX;
|
||||
store.y /= TEN_BITS_MAX;
|
||||
store.z /= TEN_BITS_MAX;
|
||||
store.w /= TWO_BITS_MAX;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector3f unsignedInt2101010RevNormalizedToFloats(
|
||||
int packedValue,
|
||||
Vector3f store
|
||||
) {
|
||||
store = unsignedInt2101010RevToFloats(packedValue, store);
|
||||
store.x /= TEN_BITS;
|
||||
store.y /= TEN_BITS;
|
||||
store.z /= TEN_BITS;
|
||||
return store;
|
||||
}
|
||||
|
||||
public static Vector4f unsignedInt2101010RevNormalizedToFloats(
|
||||
int packedValue,
|
||||
Vector4f store
|
||||
) {
|
||||
store = unsignedInt2101010RevToFloats(packedValue, store);
|
||||
store.x /= TEN_BITS;
|
||||
store.y /= TEN_BITS;
|
||||
store.z /= TEN_BITS;
|
||||
store.w /= TWO_BITS;
|
||||
return store;
|
||||
}
|
||||
}
|
||||
257
java/io/eiren/math/Vector3d.java
Normal file
257
java/io/eiren/math/Vector3d.java
Normal file
@@ -0,0 +1,257 @@
|
||||
package io.eiren.math;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
|
||||
public class Vector3d implements Cloneable {
|
||||
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
|
||||
public Vector3d() {
|
||||
}
|
||||
|
||||
public Vector3d(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector3d(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
this.x = x2 - x1;
|
||||
this.y = y2 - y1;
|
||||
this.z = z2 - z1;
|
||||
}
|
||||
|
||||
public Vector3d(Vector3f src) {
|
||||
this(src.x, src.y, src.z);
|
||||
}
|
||||
|
||||
public Vector3d set(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d set(Vector3d v) {
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
this.z = v.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d add(double addX, double addY, double addZ) {
|
||||
return new Vector3d(this.x + addX, this.y + addY, this.z + addZ);
|
||||
}
|
||||
|
||||
public Vector3d addLocal(Vector3d vec) {
|
||||
return addLocal(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
public Vector3d addLocal(double addX, double addY, double addZ) {
|
||||
x += addX;
|
||||
y += addY;
|
||||
z += addZ;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d substract(double subX, double subY, double subZ) {
|
||||
return new Vector3d(this.x - subX, this.y - subY, this.z - subZ);
|
||||
}
|
||||
|
||||
public Vector3d substractLocal(Vector3d vec) {
|
||||
if (null == vec) {
|
||||
return null;
|
||||
}
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
z -= vec.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d substractLocal(double subX, double subY, double subZ) {
|
||||
x -= subX;
|
||||
y -= subY;
|
||||
z -= subZ;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d negate() {
|
||||
return new Vector3d(-x, -y, -z);
|
||||
}
|
||||
|
||||
public Vector3d negateLocal() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d mult(double scalar) {
|
||||
return new Vector3d(x * scalar, y * scalar, z * scalar);
|
||||
}
|
||||
|
||||
public Vector3d multLocal(double scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3d divide(double scalar) {
|
||||
return new Vector3d(x / scalar, y / scalar, z / scalar);
|
||||
}
|
||||
|
||||
public Vector3d divideLocal(double scalar) {
|
||||
x /= scalar;
|
||||
y /= scalar;
|
||||
z /= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double dot(Vector3d v) {
|
||||
return x * v.x + y * v.y + z * v.z;
|
||||
}
|
||||
|
||||
public double dot(double vx, double vy, double vz) {
|
||||
return x * vx + y * vy + z * vz;
|
||||
}
|
||||
|
||||
public Vector3d cross(Vector3d other, Vector3d result) {
|
||||
if (result == null)
|
||||
result = new Vector3d();
|
||||
double resX = ((y * other.z) - (z * other.y));
|
||||
double resY = ((z * other.x) - (x * other.z));
|
||||
double resZ = ((x * other.y) - (y * other.x));
|
||||
result.set(resX, resY, resZ);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d clone() {
|
||||
return new Vector3d(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
public Vector3d normalize() {
|
||||
double length = x * x + y * y + z * z;
|
||||
if (length != 1.0 && length != 0.0) {
|
||||
double invLength = 1.0 / Math.sqrt(length);
|
||||
return mult(invLength);
|
||||
}
|
||||
return clone();
|
||||
}
|
||||
|
||||
public Vector3d normalizeLocal() {
|
||||
double length = x * x + y * y + z * z;
|
||||
if (length != 1.0 && length != 0.0) {
|
||||
length = Math.sqrt(length);
|
||||
double invLength = 1.0 / length;
|
||||
x *= invLength;
|
||||
z *= invLength;
|
||||
y *= invLength;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3f toVector3f() {
|
||||
return new Vector3f((float) x, (float) y, (float) z);
|
||||
}
|
||||
|
||||
public double length() {
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
public double lengthSquared() {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("Vector3D{")
|
||||
.append(x)
|
||||
.append(',')
|
||||
.append(y)
|
||||
.append(',')
|
||||
.append(z)
|
||||
.append('}')
|
||||
.toString();
|
||||
}
|
||||
|
||||
public void rotateAroundX(float f) {
|
||||
double f1 = Math.cos(f);
|
||||
double f2 = Math.sin(f);
|
||||
double d = x;
|
||||
double d1 = y * f1 + z * f2;
|
||||
double d2 = z * f1 - y * f2;
|
||||
x = (float) d;
|
||||
y = (float) d1;
|
||||
z = (float) d2;
|
||||
}
|
||||
|
||||
public void rotateAroundY(float f) {
|
||||
double f1 = Math.cos(f);
|
||||
double f2 = Math.sin(f);
|
||||
double d = x * f1 + z * f2;
|
||||
double d1 = y;
|
||||
double d2 = z * f1 - x * f2;
|
||||
x = (float) d;
|
||||
y = (float) d1;
|
||||
z = (float) d2;
|
||||
}
|
||||
|
||||
public double distanceTo(Vector3d vec3d) {
|
||||
return Math.sqrt(squaredDistance(vec3d));
|
||||
}
|
||||
|
||||
public double squaredDistance(Vector3d point) {
|
||||
return squaredDistance(point.x, point.y, point.z);
|
||||
}
|
||||
|
||||
public double squaredDistance(double toX, double toY, double toZ) {
|
||||
return (this.x - toX) * (this.x - toX)
|
||||
+ (this.y - toY) * (this.y - toY)
|
||||
+ (this.z - toZ) * (this.z - toZ);
|
||||
}
|
||||
|
||||
public Vector3d add(Vector3d dir) {
|
||||
return add(dir.x, dir.y, dir.z);
|
||||
}
|
||||
|
||||
public Vector3d substract(Vector3d dir) {
|
||||
return substract(dir.x, dir.y, dir.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(x);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(y);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(z);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Vector3d other = (Vector3d) obj;
|
||||
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
130
java/io/eiren/util/BufferedTimer.java
Normal file
130
java/io/eiren/util/BufferedTimer.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package io.eiren.util;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
|
||||
import com.jme3.system.NanoTimer;
|
||||
|
||||
|
||||
/**
|
||||
* This timer accumulate measured TPF and returns average/min/max FPS value
|
||||
*/
|
||||
public class BufferedTimer extends NanoTimer {
|
||||
|
||||
private final float measureInterval;
|
||||
private float averageTpf;
|
||||
private float averageFps;
|
||||
private float averageFrameRenderTime;
|
||||
private float sumFrameRenderTime;
|
||||
private float sumTpf;
|
||||
private float minFpsCurrent;
|
||||
private float maxFpsCurrent;
|
||||
private float maxFps;
|
||||
private float minFps;
|
||||
private int count;
|
||||
private boolean measured = false;
|
||||
|
||||
/**
|
||||
* Measure average tpf over the provided inverval in seconds
|
||||
*
|
||||
* @param measureInterval interval to measure averages over
|
||||
*/
|
||||
public BufferedTimer(float measureInterval) {
|
||||
averageFps = 0;
|
||||
sumTpf = 0;
|
||||
count = 0;
|
||||
this.measureInterval = measureInterval;
|
||||
}
|
||||
|
||||
public float getAverageFPS() {
|
||||
return averageFps;
|
||||
}
|
||||
|
||||
public float getMinFPS() {
|
||||
return minFps;
|
||||
}
|
||||
|
||||
public float getMaxFPS() {
|
||||
return maxFps;
|
||||
}
|
||||
|
||||
public void addRenderTime(float renderTime) {
|
||||
sumFrameRenderTime += renderTime;
|
||||
}
|
||||
|
||||
public float getAverageFrameRenderTime() {
|
||||
return averageFrameRenderTime;
|
||||
}
|
||||
|
||||
public boolean isMeasured() {
|
||||
if (measured) {
|
||||
measured = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public TimerSample getCurrentData() {
|
||||
return new TimerSample(getFrameRate(), minFps, maxFps, averageFps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
// Accumulate instant rate
|
||||
sumTpf += getTimePerFrame();
|
||||
float fps = getFrameRate();
|
||||
if (fps < minFpsCurrent)
|
||||
minFpsCurrent = fps;
|
||||
if (fps > maxFpsCurrent)
|
||||
maxFpsCurrent = fps;
|
||||
++count;
|
||||
// Calculate results once per measure interval
|
||||
if (!measured || sumTpf > measureInterval) {
|
||||
// Average results
|
||||
averageTpf = sumTpf / count;
|
||||
averageFps = 1.0f / averageTpf;
|
||||
averageFrameRenderTime = sumFrameRenderTime / count;
|
||||
minFps = minFpsCurrent;
|
||||
maxFps = maxFpsCurrent;
|
||||
// Reset counter
|
||||
sumTpf = 0;
|
||||
sumFrameRenderTime = 0;
|
||||
minFpsCurrent = Float.MAX_VALUE;
|
||||
maxFpsCurrent = 0;
|
||||
count = 0;
|
||||
measured = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TimerSample {
|
||||
|
||||
public float fps;
|
||||
public float minFps;
|
||||
public float maxFps;
|
||||
public float averageFps;
|
||||
|
||||
@ConstructorProperties({ "fps", "minFps", "maxFps", "averageFps" })
|
||||
public TimerSample(float fps, float minFps, float maxFps, float averageFps) {
|
||||
this.fps = fps;
|
||||
this.minFps = minFps;
|
||||
this.maxFps = maxFps;
|
||||
this.averageFps = averageFps;
|
||||
}
|
||||
|
||||
public float getFps() {
|
||||
return fps;
|
||||
}
|
||||
|
||||
public float getMinFps() {
|
||||
return minFps;
|
||||
}
|
||||
|
||||
public float getMaxFps() {
|
||||
return maxFps;
|
||||
}
|
||||
|
||||
public float getAverageFps() {
|
||||
return averageFps;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
java/io/eiren/util/MacOSX.java
Normal file
41
java/io/eiren/util/MacOSX.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package io.eiren.util;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Toolkit;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class MacOSX {
|
||||
|
||||
public static void setIcons(List<? extends Image> icons) {
|
||||
try {
|
||||
Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
|
||||
Method m = applicationClass.getDeclaredMethod("getApplication");
|
||||
Object application = m.invoke(null);
|
||||
m = application.getClass().getDeclaredMethod("setDockIconImage", Image.class);
|
||||
m.invoke(application, icons.get(icons.size() - 1));
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static void setTitle(String title) {
|
||||
try {
|
||||
Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
|
||||
Method m = applicationClass.getDeclaredMethod("getApplication");
|
||||
Object application = m.invoke(null);
|
||||
m = application.getClass().getDeclaredMethod("setDockIconImage", String.class);
|
||||
m.invoke(application, title);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static boolean hasRetinaDisplay() {
|
||||
Object obj = Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor");
|
||||
if (obj instanceof Float) {
|
||||
Float f = (Float) obj;
|
||||
int scale = f.intValue();
|
||||
return (scale == 2); // 1 indicates a regular mac display.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
47
java/io/eiren/util/OperatingSystem.java
Normal file
47
java/io/eiren/util/OperatingSystem.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package io.eiren.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public enum OperatingSystem {
|
||||
|
||||
//@formatter:off
|
||||
LINUX("linux", new String[]{"linux", "unix"}),
|
||||
WINDOWS("windows", new String[]{"win"}),
|
||||
OSX("osx", new String[]{"mac"}),
|
||||
UNKNOWN("unknown", new String[0]);
|
||||
//@fomatter: on
|
||||
|
||||
private final String[] aliases;
|
||||
public final String name;
|
||||
private static OperatingSystem currentPlatform;
|
||||
|
||||
private OperatingSystem(String name, String[] aliases) {
|
||||
this.aliases = aliases;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static String getJavaExecutable(boolean forceConsole) {
|
||||
String separator = System.getProperty("file.separator");
|
||||
String path = System.getProperty("java.home") + separator + "bin" + separator;
|
||||
if(getCurrentPlatform() == WINDOWS) {
|
||||
if(!forceConsole && new File(path + "javaw.exe").isFile())
|
||||
return path + "javaw.exe";
|
||||
return path + "java.exe";
|
||||
}
|
||||
return path + "java";
|
||||
}
|
||||
|
||||
public static OperatingSystem getCurrentPlatform() {
|
||||
if(currentPlatform != null)
|
||||
return currentPlatform;
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
for(OperatingSystem os : values()) {
|
||||
for(String alias : os.aliases) {
|
||||
if(osName.contains(alias))
|
||||
return currentPlatform = os;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
35
java/io/eiren/util/StringUtils.java
Normal file
35
java/io/eiren/util/StringUtils.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package io.eiren.util;
|
||||
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
private static char DECIMAL_SEP;
|
||||
|
||||
public static char getDecimalSeparator() {
|
||||
if (DECIMAL_SEP == '\u0000') {
|
||||
final Locale l = Locale.getDefault(Locale.Category.FORMAT);
|
||||
// Formatter.java always use "." in the Locale.US
|
||||
DECIMAL_SEP = (l == null || l.equals(Locale.US)
|
||||
? '.'
|
||||
: DecimalFormatSymbols.getInstance(l).getDecimalSeparator());
|
||||
}
|
||||
return DECIMAL_SEP;
|
||||
}
|
||||
|
||||
public static String prettyNumber(float f) {
|
||||
return prettyNumber(f, 4);
|
||||
}
|
||||
|
||||
public static String prettyNumber(float f, int numDigits) {
|
||||
String str = String.format("%." + numDigits + "f", f);
|
||||
if (numDigits != 0)
|
||||
str = org.apache.commons.lang3.StringUtils.stripEnd(str, "0");
|
||||
char lastChar = str.charAt(str.length() - 1);
|
||||
if (lastChar == getDecimalSeparator())
|
||||
str = str.substring(0, str.length() - 1);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
176
java/io/eiren/util/Util.java
Normal file
176
java/io/eiren/util/Util.java
Normal file
@@ -0,0 +1,176 @@
|
||||
package io.eiren.util;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class Util {
|
||||
|
||||
public static void close(Object r) {
|
||||
try {
|
||||
if (r != null) {
|
||||
if (r instanceof Closeable)
|
||||
((Closeable) r).close();
|
||||
else if (r instanceof AutoCloseable)
|
||||
((AutoCloseable) r).close();
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static void close(Object r1, Object r2) {
|
||||
close(r1);
|
||||
close(r2);
|
||||
}
|
||||
|
||||
public static void close(Object... r) {
|
||||
for (int i = 0; i < r.length; ++i)
|
||||
try {
|
||||
if (r[i] != null) {
|
||||
if (r[i] instanceof Closeable)
|
||||
((Closeable) r[i]).close();
|
||||
else if (r[i] instanceof AutoCloseable)
|
||||
((AutoCloseable) r[i]).close();
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static void close(AutoCloseable... r) {
|
||||
for (int i = 0; i < r.length; ++i)
|
||||
try {
|
||||
if (r[i] != null)
|
||||
r[i].close();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static void close(Closeable... r) {
|
||||
for (int i = 0; i < r.length; ++i)
|
||||
try {
|
||||
if (r[i] != null)
|
||||
r[i].close();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Performs a deep toString of provided object. It shows content of arrays,
|
||||
* collections and maps (trove not supported yet).
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Highly ineffective, use only for debug.</b>
|
||||
* </p>
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public static String toString(Object object) {
|
||||
if (object == null)
|
||||
return "null";
|
||||
StringBuilder buf = new StringBuilder();
|
||||
elementToString(object, buf, new HashSet<Object>());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void deepToString(Map<Object, Object> m, StringBuilder buf, Set<Object> dejaVu) {
|
||||
if (m == null) {
|
||||
buf.append("null");
|
||||
return;
|
||||
}
|
||||
if (m.size() == 0) {
|
||||
buf.append("{}");
|
||||
return;
|
||||
}
|
||||
dejaVu.add(m);
|
||||
buf.append('{');
|
||||
Iterator<Entry<Object, Object>> iterator = m.entrySet().iterator();
|
||||
boolean has = false;
|
||||
while (iterator.hasNext()) {
|
||||
if (has)
|
||||
buf.append(',');
|
||||
Entry<Object, Object> e = iterator.next();
|
||||
elementToString(e.getKey(), buf, dejaVu);
|
||||
buf.append(':');
|
||||
elementToString(e.getValue(), buf, dejaVu);
|
||||
has = true;
|
||||
}
|
||||
buf.append('}');
|
||||
dejaVu.remove(m);
|
||||
}
|
||||
|
||||
private static void deepToString(
|
||||
Collection<Object> list,
|
||||
StringBuilder buf,
|
||||
Set<Object> dejaVu
|
||||
) {
|
||||
Object[] array = list.toArray();
|
||||
deepToString(array, buf, dejaVu);
|
||||
}
|
||||
|
||||
private static void deepToString(Object[] a, StringBuilder buf, Set<Object> dejaVu) {
|
||||
if (a == null) {
|
||||
buf.append("null");
|
||||
return;
|
||||
}
|
||||
if (a.length == 0) {
|
||||
buf.append("[]");
|
||||
return;
|
||||
}
|
||||
dejaVu.add(a);
|
||||
buf.append('[');
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (i != 0)
|
||||
buf.append(',');
|
||||
Object element = a[i];
|
||||
elementToString(element, buf, dejaVu);
|
||||
}
|
||||
buf.append(']');
|
||||
dejaVu.remove(a);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void elementToString(Object element, StringBuilder buf, Set<Object> dejaVu) {
|
||||
if (element == null) {
|
||||
buf.append("null");
|
||||
} else {
|
||||
Class<?> eClass = element.getClass();
|
||||
if (eClass.isArray()) {
|
||||
if (eClass == byte[].class)
|
||||
buf.append(Arrays.toString((byte[]) element));
|
||||
else if (eClass == short[].class)
|
||||
buf.append(Arrays.toString((short[]) element));
|
||||
else if (eClass == int[].class)
|
||||
buf.append(Arrays.toString((int[]) element));
|
||||
else if (eClass == long[].class)
|
||||
buf.append(Arrays.toString((long[]) element));
|
||||
else if (eClass == char[].class)
|
||||
buf.append(Arrays.toString((char[]) element));
|
||||
else if (eClass == float[].class)
|
||||
buf.append(Arrays.toString((float[]) element));
|
||||
else if (eClass == double[].class)
|
||||
buf.append(Arrays.toString((double[]) element));
|
||||
else if (eClass == boolean[].class)
|
||||
buf.append(Arrays.toString((boolean[]) element));
|
||||
else { // element is an array of object references
|
||||
if (dejaVu.contains(element))
|
||||
buf.append("[...]");
|
||||
else
|
||||
deepToString((Object[]) element, buf, dejaVu);
|
||||
}
|
||||
} else { // element is non-null and not an array
|
||||
if (element instanceof Collection)
|
||||
deepToString((Collection<Object>) element, buf, dejaVu);
|
||||
else if (element instanceof Map)
|
||||
deepToString((Map<Object, Object>) element, buf, dejaVu);
|
||||
else if (element instanceof CharSequence)
|
||||
buf.append('"').append(element.toString()).append('"');
|
||||
else
|
||||
buf.append(element.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
java/io/eiren/util/ann/AWTThread.java
Normal file
10
java/io/eiren/util/ann/AWTThread.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface AWTThread {
|
||||
|
||||
}
|
||||
9
java/io/eiren/util/ann/DebugSwitch.java
Normal file
9
java/io/eiren/util/ann/DebugSwitch.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
public @interface DebugSwitch {
|
||||
}
|
||||
19
java/io/eiren/util/ann/NativeUnsafe.java
Normal file
19
java/io/eiren/util/ann/NativeUnsafe.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* Marks methods and classes that use unsafe or direct access to memory. Proceed
|
||||
* with caution.
|
||||
*
|
||||
* @author Rena
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface NativeUnsafe {
|
||||
|
||||
}
|
||||
30
java/io/eiren/util/ann/Synchronize.java
Normal file
30
java/io/eiren/util/ann/Synchronize.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Означает необходимость обязательной синхронизации этого меcта во внешних
|
||||
* методах. В аргументах передаётся название поля для синхронизации.
|
||||
* </p>
|
||||
* <p>
|
||||
* Методы, помеченные данной аннотацией могут вызывать только Thread-Safe
|
||||
* методы, либо методы, помеченные такой же аннотацией с тем же полем
|
||||
* синхронизации.
|
||||
* </p>
|
||||
* <p>
|
||||
* Поля, помеченные данной аннотацией должны быть синхронизированны на указанное
|
||||
* поле при чтении или записи.
|
||||
* </p>
|
||||
*
|
||||
* @see {@link ThreadSafe}, {@link ThreadSecure}, {@link ThreadSafeSingle}
|
||||
* @author Rena
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface Synchronize {
|
||||
|
||||
String[] value();
|
||||
|
||||
}
|
||||
27
java/io/eiren/util/ann/ThreadSafe.java
Normal file
27
java/io/eiren/util/ann/ThreadSafe.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Методы, помеченные этой аннотацией должны быть Thread-Safe.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Важно:</b> данные методы гарантированно должны обеспечивать потоковую
|
||||
* безопасность, но не обязаны обеспечивать концессивность (полноту данных или
|
||||
* точность синхронизации).
|
||||
* </p>
|
||||
* <p>
|
||||
* Для полностью потоко-безопасных методов можно использовать аннотацию
|
||||
* {@link ThreadSecure}.
|
||||
* </p>
|
||||
*
|
||||
* @see {@link ThreadSecure}, {@link Synchronize}, {@link ThreadSafeSingle}
|
||||
* @author Rena
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface ThreadSafe {
|
||||
|
||||
}
|
||||
17
java/io/eiren/util/ann/ThreadSafeSingle.java
Normal file
17
java/io/eiren/util/ann/ThreadSafeSingle.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* Соблюдает те же требования что и {@link ThreadSafe} но при условии, что сам
|
||||
* метод вызывается только из одного потока одновременно.
|
||||
*
|
||||
* @see {@link ThreadSafe}, {@link ThreadSecure}, {@link Synchronize}
|
||||
* @author Rena
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface ThreadSafeSingle {
|
||||
|
||||
}
|
||||
22
java/io/eiren/util/ann/ThreadSecure.java
Normal file
22
java/io/eiren/util/ann/ThreadSecure.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Методы, помеченные этой аннотацией должны быть полностью Thread-Safe.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Важно:</b> данные методы гарантированно должны обеспечивать потоковую
|
||||
* безопасность и консистентность (полноту данных и точность синхронизации).
|
||||
* </p>
|
||||
*
|
||||
* @see {@link ThreadSafe}, {@link Synchronize}, {@link ThreadSafeSingle}
|
||||
* @author Rena
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface ThreadSecure {
|
||||
|
||||
}
|
||||
39
java/io/eiren/util/ann/Transient.java
Normal file
39
java/io/eiren/util/ann/Transient.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package io.eiren.util.ann;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Означает что поле используется для временных или быстро изменяющихся
|
||||
* переменных.
|
||||
* </p>
|
||||
* <p>
|
||||
* Поле помеченное этой аннотацией не влияет на долгосрочное состояние объекта,
|
||||
* не участвует в сериализации, вычислении equals и hashCode, не определяет
|
||||
* поведение объекта для внешнего кода. Поэтому такие поля не должны
|
||||
* использоваться внешним кодом, их состояние имеет смысл только для самого
|
||||
* объекта в котором они объявлены.
|
||||
* </p>
|
||||
* Примеры:
|
||||
* <ul>
|
||||
* <li>Временный объект, который используется в методах для внутренних
|
||||
* вычислений. Например векторные и матричные вычисления.</li>
|
||||
* <li>Внутренний флаг для мультитрединга. Например, флаг апдейта графического
|
||||
* состояния взводимый из игрового потока.</li>
|
||||
* <li>Выведенное значение или структура, которое инициализируется самим
|
||||
* объектом по фиксированному правилу. Например, производное значение от
|
||||
* переменной параметризующей объект. Инициализируемый в конструкторе lookup
|
||||
* table.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author tort32
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
@Target({ ElementType.FIELD })
|
||||
public @interface Transient {
|
||||
|
||||
}
|
||||
547
java/io/eiren/util/collections/FastList.java
Normal file
547
java/io/eiren/util/collections/FastList.java
Normal file
@@ -0,0 +1,547 @@
|
||||
package io.eiren.util.collections;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class FastList<E> extends AbstractList<E>
|
||||
implements RandomAccess, Cloneable, RemoveAtSwapList<E> {
|
||||
|
||||
private static final Object[] emptyArray = new Object[0];
|
||||
|
||||
public static final int MAX_ARRAY_SIZE = 2147483639;
|
||||
|
||||
protected int size = 0;
|
||||
protected Object[] array;
|
||||
|
||||
public FastList(int capacity) {
|
||||
array = capacity == 0 ? emptyArray : new Object[capacity];
|
||||
}
|
||||
|
||||
public FastList() {
|
||||
this(5);
|
||||
}
|
||||
|
||||
public FastList(Collection<E> source) {
|
||||
this(source.size());
|
||||
addAll(source);
|
||||
}
|
||||
|
||||
public FastList(FastList<E> source) {
|
||||
this(source.size);
|
||||
addAllInternal(0, source.array, source.size);
|
||||
}
|
||||
|
||||
public FastList(E[] source) {
|
||||
this(source.length);
|
||||
addAll(source);
|
||||
}
|
||||
|
||||
public FastList(E source) {
|
||||
this();
|
||||
add(source);
|
||||
}
|
||||
|
||||
private FastList(Object[] arr, int size) {
|
||||
this(size);
|
||||
System.arraycopy(arr, 0, array, 0, size);
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
private FastList(boolean f) {
|
||||
}
|
||||
|
||||
public static <E> FastList<E> reuseArray(E[] source) {
|
||||
FastList<E> list = new FastList<>(true);
|
||||
list.array = source;
|
||||
list.size = source.length;
|
||||
return list;
|
||||
}
|
||||
|
||||
private void checkBounds(int index) {
|
||||
if (index < 0 || index >= size)
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
new StringBuilder("Index: ")
|
||||
.append(index)
|
||||
.append(", size: ")
|
||||
.append(size)
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
|
||||
public void ensureCapacity(int numToFit) {
|
||||
if (array.length < size + numToFit)
|
||||
grow(numToFit + size);
|
||||
}
|
||||
|
||||
private void grow(int i) {
|
||||
int j = array.length;
|
||||
int k = j + (j >> 1);
|
||||
if (k - i < 0)
|
||||
k = i;
|
||||
if (k - 2147483639 > 0)
|
||||
k = hugeCapacity(i);
|
||||
array = Arrays.copyOf(array, k);
|
||||
}
|
||||
|
||||
private static int hugeCapacity(int i) {
|
||||
if (i < 0)
|
||||
throw new OutOfMemoryError("Huge capacity negative: " + i);
|
||||
else
|
||||
return i <= MAX_ARRAY_SIZE ? MAX_ARRAY_SIZE : 2147483647;
|
||||
}
|
||||
|
||||
public void copyInto(Object[] anArray) {
|
||||
System.arraycopy(array, 0, anArray, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
checkBounds(index);
|
||||
return (E) array[index];
|
||||
}
|
||||
|
||||
public E unsafeGet(int index) {
|
||||
return (E) array[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object obj) {
|
||||
for (int j = 0; j < size; j++)
|
||||
if (obj == array[j])
|
||||
return j;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object obj) {
|
||||
for (int j = size - 1; j >= 0; j--)
|
||||
if (obj == array[j])
|
||||
return j;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object obj) {
|
||||
return indexOf(obj) >= 0;
|
||||
}
|
||||
|
||||
public void trimToSize() {
|
||||
int i = array.length;
|
||||
if (size < i)
|
||||
array = Arrays.copyOf(array, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return Arrays.copyOf(array, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T aobj[]) {
|
||||
if (aobj.length < size)
|
||||
return (T[]) Arrays.copyOf(array, size, aobj.getClass());
|
||||
System.arraycopy(array, 0, aobj, 0, size);
|
||||
if (aobj.length > size)
|
||||
aobj[size] = null;
|
||||
return aobj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
ensureCapacity(1);
|
||||
array[size++] = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int i) {
|
||||
checkBounds(i);
|
||||
E obj = (E) array[i];
|
||||
removeInternal(i);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object obj) {
|
||||
for (int j = 0; j < size; j++)
|
||||
if (obj == array[j]) {
|
||||
removeInternal(j);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeAll(Object[] toRemove) {
|
||||
boolean removed = false;
|
||||
for (int i = toRemove.length - 1; i >= 0; --i) {
|
||||
int index = indexOf(toRemove[i]);
|
||||
if (index != -1) {
|
||||
removeInternal(index);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
protected void removeInternal(int i) {
|
||||
int j = size - i - 1;
|
||||
if (j > 0)
|
||||
System.arraycopy(array, i + 1, array, i, j);
|
||||
array[--size] = null;
|
||||
}
|
||||
|
||||
public void unsafeRemove(int i) {
|
||||
removeInternal(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
Objects.requireNonNull(c);
|
||||
return batchRemove(c, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
Objects.requireNonNull(c);
|
||||
return batchRemove(c, true);
|
||||
}
|
||||
|
||||
private boolean batchRemove(Collection<?> c, boolean complement) {
|
||||
final Object[] elementData = this.array;
|
||||
int r = 0, w = 0;
|
||||
boolean modified = false;
|
||||
try {
|
||||
for (; r < size; r++)
|
||||
if (c.contains(elementData[r]) == complement)
|
||||
elementData[w++] = elementData[r];
|
||||
} finally {
|
||||
// Preserve behavioral compatibility with AbstractCollection,
|
||||
// even if c.contains() throws.
|
||||
if (r != size) {
|
||||
System.arraycopy(elementData, r, elementData, w, size - r);
|
||||
w += size - r;
|
||||
}
|
||||
if (w != size) {
|
||||
for (int i = w; i < size; i++)
|
||||
elementData[i] = null;
|
||||
size = w;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for (int i = 0; i < size; i++)
|
||||
array[i] = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public void fakeClear() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
return addAll(size, collection);
|
||||
}
|
||||
|
||||
public void addAll(E[] arr) {
|
||||
addAllInternal(size, arr, arr.length);
|
||||
}
|
||||
|
||||
public void addAll(E[] arr, int limit) {
|
||||
addAllInternal(size, arr, limit);
|
||||
}
|
||||
|
||||
public void addAll(int index, E[] arr) {
|
||||
addAllInternal(index, arr, arr.length);
|
||||
}
|
||||
|
||||
public void addAll(int index, E[] arr, int limit) {
|
||||
addAllInternal(index, arr, limit);
|
||||
}
|
||||
|
||||
private void addAllInternal(int index, Object[] arr, int limit) {
|
||||
if (limit > arr.length)
|
||||
limit = arr.length;
|
||||
if (limit == 1) {
|
||||
add(index, (E) arr[0]);
|
||||
} else if (limit > 0) {
|
||||
if (index >= size) {
|
||||
ensureCapacity(size - index + limit);
|
||||
System.arraycopy(arr, 0, array, index, limit);
|
||||
size = index + limit;
|
||||
} else {
|
||||
if (array.length < size + limit) {
|
||||
Object[] newArray = new Object[size + limit];
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
System.arraycopy(arr, 0, newArray, index, limit);
|
||||
System.arraycopy(array, index, newArray, index + limit, size - index);
|
||||
array = newArray;
|
||||
} else {
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
System.arraycopy(arr, 0, array, index, limit);
|
||||
}
|
||||
size += limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> collection) {
|
||||
if (collection.size() > 0) {
|
||||
if (collection instanceof FastList) {
|
||||
addAllInternal(
|
||||
index,
|
||||
((FastList<? extends E>) collection).array,
|
||||
collection.size()
|
||||
);
|
||||
} else if (collection instanceof RandomAccess) {
|
||||
Object[] arr = collection.toArray(new Object[collection.size()]);
|
||||
addAllInternal(index, arr, arr.length);
|
||||
} else {
|
||||
if (index >= size) {
|
||||
ensureCapacity(size - index + collection.size());
|
||||
Iterator<? extends E> iterator = collection.iterator();
|
||||
int i = index;
|
||||
while (iterator.hasNext())
|
||||
array[i++] = iterator.next();
|
||||
size = index + collection.size();
|
||||
} else {
|
||||
if (array.length < size + collection.size()) {
|
||||
Object[] newArray = new Object[size + collection.size()];
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
Iterator<? extends E> iterator = collection.iterator();
|
||||
int i = index;
|
||||
while (iterator.hasNext())
|
||||
newArray[i++] = iterator.next();
|
||||
System
|
||||
.arraycopy(
|
||||
array,
|
||||
index,
|
||||
newArray,
|
||||
index + collection.size(),
|
||||
size - index
|
||||
);
|
||||
array = newArray;
|
||||
} else {
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
Iterator<? extends E> iterator = collection.iterator();
|
||||
while (iterator.hasNext())
|
||||
array[index++] = iterator.next();
|
||||
}
|
||||
size += collection.size();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
if (index >= size) {
|
||||
ensureCapacity(size - index + 1);
|
||||
size = index + 1;
|
||||
array[index] = element;
|
||||
} else {
|
||||
if (array.length < size + 1) {
|
||||
Object[] newArray = new Object[size + 1];
|
||||
System.arraycopy(array, 0, newArray, 0, index);
|
||||
newArray[index] = element;
|
||||
System.arraycopy(array, index, newArray, index + 1, size - index);
|
||||
array = newArray;
|
||||
} else {
|
||||
System.arraycopy(array, index, array, index + 1, size - index);
|
||||
array[index] = element;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
checkBounds(index);
|
||||
E oldValue = (E) array[index];
|
||||
array[index] = element;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastList<E> clone() {
|
||||
return new FastList<E>(array, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super E> action) {
|
||||
Objects.requireNonNull(action);
|
||||
final int expectedModCount = modCount;
|
||||
final E[] elementData = (E[]) this.array;
|
||||
final int size = this.size;
|
||||
for (int i = 0; modCount == expectedModCount && i < size; i++) {
|
||||
action.accept(elementData[i]);
|
||||
}
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeAtSwap(int i) {
|
||||
checkBounds(i);
|
||||
E obj = (E) array[i];
|
||||
removeAtSwapInternal(i);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAtSwap(Object obj) {
|
||||
for (int j = 0; j < size; j++)
|
||||
if (obj == array[j]) {
|
||||
removeAtSwapInternal(j);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void removeAtSwapInternal(int i) {
|
||||
int j = size - i - 1;
|
||||
if (j > 0)
|
||||
array[i] = array[size - 1];
|
||||
array[--size] = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRange(int i, int toIndex) {
|
||||
checkBounds(i);
|
||||
checkBounds(toIndex);
|
||||
int j = size - toIndex - 1;
|
||||
if (j > 0)
|
||||
System.arraycopy(array, toIndex + 1, array, i, j);
|
||||
size -= (toIndex - i + 1);
|
||||
Arrays.fill(array, i, toIndex, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAll(UnaryOperator<E> operator) {
|
||||
Objects.requireNonNull(operator);
|
||||
for (int i = 0; i < size; ++i)
|
||||
set(i, operator.apply(get(i)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Comparator<? super E> c) {
|
||||
Arrays.sort((E[]) array, 0, size, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 1;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
Object o = array[i];
|
||||
hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator(array, 0, size, Spliterator.ORDERED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special comodification iterator. <b>Use with caution.</b>
|
||||
* <p>
|
||||
* <i>To get element type correctly assign result to reference type
|
||||
* {@code FastList<T>.SkipFastListIterator}</i>
|
||||
*
|
||||
* @return skip iterator to iterate this list in thread-safe manner
|
||||
*/
|
||||
public SkipFastListIterator skipIterator() {
|
||||
return new SkipFastListIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super E> filter) {
|
||||
Objects.requireNonNull(filter);
|
||||
// figure out which elements are to be removed
|
||||
// any exception thrown from the filter predicate at this stage
|
||||
// will leave the collection unmodified
|
||||
int removeCount = 0;
|
||||
final BitSet removeSet = new BitSet(size);
|
||||
final int expectedModCount = modCount;
|
||||
final int size = this.size;
|
||||
for (int i = 0; modCount == expectedModCount && i < size; i++) {
|
||||
final E element = (E) array[i];
|
||||
if (filter.test(element)) {
|
||||
removeSet.set(i);
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
// shift surviving elements left over the spaces left by removed
|
||||
// elements
|
||||
final boolean anyToRemove = removeCount > 0;
|
||||
if (anyToRemove) {
|
||||
final int newSize = size - removeCount;
|
||||
for (int i = 0, j = 0; (i < size) && (j < newSize); i++, j++) {
|
||||
i = removeSet.nextClearBit(i);
|
||||
array[j] = array[i];
|
||||
}
|
||||
for (int k = newSize; k < size; k++) {
|
||||
array[k] = null; // Let gc do its work
|
||||
}
|
||||
this.size = newSize;
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
modCount++;
|
||||
}
|
||||
|
||||
return anyToRemove;
|
||||
}
|
||||
|
||||
public class SkipFastListIterator implements ResettableIterator<E>, SkipIterator<E> {
|
||||
|
||||
public int position;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return position < size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
Object[] arr = array;
|
||||
if (arr.length > position) {
|
||||
return (E) arr[position++];
|
||||
}
|
||||
position++; // Increase position so hasNext() never loops infinitely
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
java/io/eiren/util/collections/RemoveAtSwapFastList.java
Normal file
41
java/io/eiren/util/collections/RemoveAtSwapFastList.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package io.eiren.util.collections;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
/**
|
||||
* FastList that performs Remove-At-Swap on stanard remove() operations.
|
||||
*
|
||||
* <p>
|
||||
* Remove operations breaks ordering of this list
|
||||
*
|
||||
* @author Rena
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
public class RemoveAtSwapFastList<E> extends FastList<E> {
|
||||
|
||||
public RemoveAtSwapFastList(int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
|
||||
public RemoveAtSwapFastList() {
|
||||
}
|
||||
|
||||
public RemoveAtSwapFastList(Collection<E> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public RemoveAtSwapFastList(E[] source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public RemoveAtSwapFastList(E source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeInternal(int i) {
|
||||
super.removeAtSwapInternal(i);
|
||||
}
|
||||
}
|
||||
11
java/io/eiren/util/collections/RemoveAtSwapList.java
Normal file
11
java/io/eiren/util/collections/RemoveAtSwapList.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package io.eiren.util.collections;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface RemoveAtSwapList<E> extends List<E> {
|
||||
|
||||
public E removeAtSwap(int i);
|
||||
|
||||
public boolean removeAtSwap(Object object);
|
||||
}
|
||||
17
java/io/eiren/util/collections/ResettableIterator.java
Normal file
17
java/io/eiren/util/collections/ResettableIterator.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package io.eiren.util.collections;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* {@link Iterator} that can be reset and iterated from the start by using
|
||||
* {@link #reset()}
|
||||
*
|
||||
* @author Rena
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
public interface ResettableIterator<E> extends Iterator<E> {
|
||||
|
||||
public void reset();
|
||||
}
|
||||
16
java/io/eiren/util/collections/SkipIterator.java
Normal file
16
java/io/eiren/util/collections/SkipIterator.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package io.eiren.util.collections;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* {@link Iterator} that can return null on {@link #next()} or can lie on
|
||||
* {@link #hasNext()}. It is <b>not thread-secure!</b>
|
||||
*
|
||||
* @param <E> the type of elements returned by this iterator
|
||||
*/
|
||||
public interface SkipIterator<E> extends Iterator<E> {
|
||||
|
||||
@Override
|
||||
E next();
|
||||
}
|
||||
137
java/io/eiren/util/logging/DefaultGLog.java
Normal file
137
java/io/eiren/util/logging/DefaultGLog.java
Normal file
@@ -0,0 +1,137 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
public class DefaultGLog extends Thread implements IGLog {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public static class LogEntry {
|
||||
|
||||
private Level level;
|
||||
private String message;
|
||||
private Throwable t;
|
||||
|
||||
public LogEntry(Level level, String message, Throwable t) {
|
||||
this(level, message);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public LogEntry(Level level, String message) {
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.t = null;
|
||||
}
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Throwable getException() {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayBlockingQueue<LogEntry> queue = new ArrayBlockingQueue<LogEntry>(50000);
|
||||
private volatile LoggerRecorder recorder;
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
add(new LogEntry(Level.INFO, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message, Throwable t) {
|
||||
add(new LogEntry(Level.INFO, message, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message) {
|
||||
add(new LogEntry(Level.SEVERE, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message, Throwable t) {
|
||||
add(new LogEntry(Level.SEVERE, message, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String message) {
|
||||
add(new LogEntry(Level.WARNING, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String message, Throwable t) {
|
||||
add(new LogEntry(Level.WARNING, message, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
add(new LogEntry(Level.INFO, "[DBG] " + message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String message, Throwable t) {
|
||||
add(new LogEntry(Level.INFO, "[DBG] " + message, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String message) {
|
||||
add(new LogEntry(level, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String message, Throwable t) {
|
||||
add(new LogEntry(level, message, t));
|
||||
}
|
||||
|
||||
private void add(LogEntry entry) {
|
||||
try {
|
||||
queue.put(entry);
|
||||
} catch (InterruptedException e) {}
|
||||
try {
|
||||
if (recorder != null)
|
||||
recorder.addEntry(entry);
|
||||
} catch (NullPointerException e) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecorder(LoggerRecorder recorder) {
|
||||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggerRecorder removeRecorder() {
|
||||
LoggerRecorder lr = this.recorder;
|
||||
this.recorder = null;
|
||||
return lr;
|
||||
}
|
||||
|
||||
public DefaultGLog(Logger logger) {
|
||||
super("Logger");
|
||||
this.logger = logger;
|
||||
this.setDaemon(true);
|
||||
this.setPriority(7);
|
||||
this.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
LogEntry log = queue.take();
|
||||
if (log.t != null)
|
||||
logger.log(log.level, log.message, log.t);
|
||||
else
|
||||
logger.log(log.level, log.message);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
java/io/eiren/util/logging/FileLogFormatter.java
Normal file
58
java/io/eiren/util/logging/FileLogFormatter.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
|
||||
public class FileLogFormatter extends Formatter {
|
||||
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(dateFormat.format(record.getMillis()));
|
||||
Level localLevel = record.getLevel();
|
||||
if (localLevel == Level.FINEST)
|
||||
sb.append(" [FINEST] ");
|
||||
else if (localLevel == Level.FINER)
|
||||
sb.append(" [FINER] ");
|
||||
else if (localLevel == Level.FINE)
|
||||
sb.append(" [FINE] ");
|
||||
else if (localLevel == Level.INFO)
|
||||
sb.append(" [INFO] ");
|
||||
else if (localLevel == Level.WARNING)
|
||||
sb.append(" [WARNING] ");
|
||||
else if (localLevel == Level.SEVERE)
|
||||
sb.append(" [SEVERE] ");
|
||||
else
|
||||
sb.append(" [" + localLevel.getLocalizedName() + "] ");
|
||||
|
||||
sb.append(record.getMessage());
|
||||
sb.append('\n');
|
||||
|
||||
Throwable localThrowable = record.getThrown();
|
||||
if (localThrowable != null) {
|
||||
StringWriter localStringWriter = new StringWriter();
|
||||
localThrowable.printStackTrace(new PrintWriter(localStringWriter));
|
||||
sb.append(localStringWriter.toString());
|
||||
}
|
||||
|
||||
String message = sb.toString();
|
||||
Object parameters[] = record.getParameters();
|
||||
if (parameters == null || parameters.length == 0)
|
||||
return message;
|
||||
if (
|
||||
message.indexOf("{0") >= 0
|
||||
|| message.indexOf("{1") >= 0
|
||||
|| message.indexOf("{2") >= 0
|
||||
|| message.indexOf("{3") >= 0
|
||||
)
|
||||
return java.text.MessageFormat.format(message, parameters);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
48
java/io/eiren/util/logging/IGLog.java
Normal file
48
java/io/eiren/util/logging/IGLog.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
public interface IGLog {
|
||||
|
||||
public void info(String message);
|
||||
|
||||
public void severe(String message);
|
||||
|
||||
public void warning(String message);
|
||||
|
||||
public void debug(String message);
|
||||
|
||||
public default void info(String message, Throwable t) {
|
||||
log(Level.INFO, message, t);
|
||||
}
|
||||
|
||||
public default void severe(String message, Throwable t) {
|
||||
log(Level.SEVERE, message, t);
|
||||
}
|
||||
|
||||
public default void warning(String message, Throwable t) {
|
||||
log(Level.WARNING, message, t);
|
||||
}
|
||||
|
||||
public default void debug(String message, Throwable t) {
|
||||
log(Level.INFO, "[DBG] " + message, t);
|
||||
}
|
||||
|
||||
public void log(Level level, String message);
|
||||
|
||||
public void log(Level level, String message, Throwable t);
|
||||
|
||||
public void setRecorder(LoggerRecorder recorder);
|
||||
|
||||
public LoggerRecorder removeRecorder();
|
||||
|
||||
static class GLevel extends Level {
|
||||
|
||||
private static final long serialVersionUID = -539856764608026895L;
|
||||
|
||||
private GLevel(String s, int i) {
|
||||
super(s, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
136
java/io/eiren/util/logging/LogManager.java
Normal file
136
java/io/eiren/util/logging/LogManager.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.ConsoleHandler;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
public class LogManager {
|
||||
|
||||
private static AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
public static Logger global = Logger.getLogger("");
|
||||
public static final IGLog log = new DefaultGLog(global);
|
||||
public static ConsoleHandler handler;
|
||||
|
||||
public static void initialize(File logsDir, File mainLogDir)
|
||||
throws SecurityException, IOException {
|
||||
if (initialized.getAndSet(true))
|
||||
return;
|
||||
FileLogFormatter loc = new FileLogFormatter();
|
||||
if (mainLogDir != null) {
|
||||
if (!mainLogDir.exists())
|
||||
mainLogDir.mkdirs();
|
||||
File lastLogFile = new File(mainLogDir, "log_last.log");
|
||||
if (lastLogFile.exists())
|
||||
lastLogFile.delete();
|
||||
File mainLog = new File(mainLogDir, "log_main.log");
|
||||
FileHandler mHandler = new FileHandler(mainLog.getPath(), true);
|
||||
FileHandler filehandler = new FileHandler(lastLogFile.getPath(), true);
|
||||
mHandler.setFormatter(loc);
|
||||
filehandler.setFormatter(loc);
|
||||
global.addHandler(mHandler);
|
||||
global.addHandler(filehandler);
|
||||
}
|
||||
if (logsDir != null) {
|
||||
if (!logsDir.exists())
|
||||
logsDir.mkdir();
|
||||
if (!logsDir.isDirectory())
|
||||
System.out.println("*** WARNING *** LOG FOLDER IS NOT A DIRECTORY!");
|
||||
File currentLog = new File(
|
||||
logsDir,
|
||||
"log_"
|
||||
+ new SimpleDateFormat("yyyy-MM-dd")
|
||||
.format(Long.valueOf(System.currentTimeMillis()))
|
||||
+ ".log"
|
||||
);
|
||||
FileHandler filehandler2 = new FileHandler(currentLog.getPath(), true);
|
||||
filehandler2.setFormatter(loc);
|
||||
global.addHandler(filehandler2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceMainHandler(ConsoleHandler newHandler) {
|
||||
handler.close();
|
||||
global.removeHandler(handler);
|
||||
handler = newHandler;
|
||||
global.addHandler(newHandler);
|
||||
}
|
||||
|
||||
public static void addHandler(Handler add) {
|
||||
global.addHandler(add);
|
||||
}
|
||||
|
||||
public static void removeHandler(Handler remove) {
|
||||
global.removeHandler(remove);
|
||||
}
|
||||
|
||||
public static void enablePreciseTimestamp() {
|
||||
handler.setFormatter(new PreciseConsoleLogFormatter());
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
log.info(message);
|
||||
}
|
||||
|
||||
public static void severe(String message) {
|
||||
log.severe(message);
|
||||
}
|
||||
|
||||
public static void warning(String message) {
|
||||
log.warning(message);
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
public static void info(String message, Throwable t) {
|
||||
log.info(message, t);
|
||||
}
|
||||
|
||||
public static void severe(String message, Throwable t) {
|
||||
log.severe(message, t);
|
||||
}
|
||||
|
||||
public static void warning(String message, Throwable t) {
|
||||
log.warning(message, t);
|
||||
}
|
||||
|
||||
public static void debug(String message, Throwable t) {
|
||||
log.debug(message, t);
|
||||
}
|
||||
|
||||
public static void log(Level level, String message) {
|
||||
log.log(level, message);
|
||||
}
|
||||
|
||||
public static void log(Level level, String message, Throwable t) {
|
||||
log.log(level, message, t);
|
||||
}
|
||||
|
||||
static {
|
||||
boolean hasConsoleHandler = false;
|
||||
for (Handler h : global.getHandlers()) {
|
||||
if (h instanceof ConsoleHandler) {
|
||||
handler = (ConsoleHandler) h;
|
||||
hasConsoleHandler = true;
|
||||
}
|
||||
}
|
||||
if (!hasConsoleHandler) {
|
||||
handler = new ConsoleHandler();
|
||||
global.addHandler(handler);
|
||||
}
|
||||
handler.setFormatter(new ShortConsoleLogFormatter());
|
||||
|
||||
System.setOut(new PrintStream(new LoggerOutputStream(log, Level.INFO), true));
|
||||
System.setErr(new PrintStream(new LoggerOutputStream(log, Level.SEVERE), true));
|
||||
}
|
||||
}
|
||||
52
java/io/eiren/util/logging/LoggerOutputStream.java
Normal file
52
java/io/eiren/util/logging/LoggerOutputStream.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
public class LoggerOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
private static final String separator = System.getProperty("line.separator");
|
||||
|
||||
private final IGLog logger;
|
||||
private final Level level;
|
||||
private final String prefix;
|
||||
private final StringBuilder buffer = new StringBuilder();
|
||||
|
||||
public LoggerOutputStream(IGLog logger, Level level) {
|
||||
this(logger, level, "");
|
||||
}
|
||||
|
||||
public LoggerOutputStream(IGLog logger, Level level, String prefix) {
|
||||
super();
|
||||
this.logger = logger;
|
||||
this.level = level;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
synchronized (this) {
|
||||
super.flush();
|
||||
String record = this.toString();
|
||||
super.reset();
|
||||
if (record.length() > 0) {
|
||||
buffer.append(record);
|
||||
if (record.contains(separator)) {
|
||||
String s = buffer.toString();
|
||||
String[] split = s.split(separator);
|
||||
for (int i = 0; i < split.length; ++i)
|
||||
logger.log(level, prefix + split[i]);
|
||||
buffer.setLength(0);
|
||||
// buffer.append(split[split.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
23
java/io/eiren/util/logging/LoggerRecorder.java
Normal file
23
java/io/eiren/util/logging/LoggerRecorder.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.DefaultGLog.LogEntry;
|
||||
|
||||
|
||||
public class LoggerRecorder {
|
||||
|
||||
private final List<LogEntry> recorded = new FastList<LogEntry>();
|
||||
|
||||
public LoggerRecorder() {
|
||||
}
|
||||
|
||||
public synchronized void addEntry(LogEntry e) {
|
||||
recorded.add(e);
|
||||
}
|
||||
|
||||
public List<LogEntry> getEntries() {
|
||||
return recorded;
|
||||
}
|
||||
}
|
||||
32
java/io/eiren/util/logging/PreciseConsoleLogFormatter.java
Normal file
32
java/io/eiren/util/logging/PreciseConsoleLogFormatter.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
|
||||
/**
|
||||
* Format message timestamp as time passed from the start with milliseconds.
|
||||
*/
|
||||
public class PreciseConsoleLogFormatter extends ShortConsoleLogFormatter {
|
||||
|
||||
private final long startMills;
|
||||
|
||||
public PreciseConsoleLogFormatter() {
|
||||
startMills = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleDateFormat createDateFormat() {
|
||||
return new SimpleDateFormat("mm:ss.SSS");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildMessage(StringBuilder builder, LogRecord record) {
|
||||
builder.append(date.format(record.getMillis() - startMills));
|
||||
builder.append(" [");
|
||||
builder.append(record.getLevel().getLocalizedName().toUpperCase());
|
||||
builder.append("] ");
|
||||
builder.append(record.getMessage());
|
||||
builder.append('\n');
|
||||
}
|
||||
}
|
||||
58
java/io/eiren/util/logging/ShortConsoleLogFormatter.java
Normal file
58
java/io/eiren/util/logging/ShortConsoleLogFormatter.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package io.eiren.util.logging;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
|
||||
public class ShortConsoleLogFormatter extends Formatter {
|
||||
|
||||
protected final SimpleDateFormat date;
|
||||
|
||||
public ShortConsoleLogFormatter() {
|
||||
this.date = createDateFormat();
|
||||
}
|
||||
|
||||
protected SimpleDateFormat createDateFormat() {
|
||||
return new SimpleDateFormat("HH:mm:ss");
|
||||
}
|
||||
|
||||
protected void buildMessage(StringBuilder builder, LogRecord record) {
|
||||
builder.append(date.format(record.getMillis()));
|
||||
builder.append(" [");
|
||||
builder.append(record.getLevel().getLocalizedName().toUpperCase());
|
||||
builder.append("] ");
|
||||
builder.append(record.getMessage());
|
||||
builder.append('\n');
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Throwable ex = record.getThrown();
|
||||
|
||||
buildMessage(builder, record);
|
||||
|
||||
if (ex != null) {
|
||||
StringWriter writer = new StringWriter();
|
||||
ex.printStackTrace(new PrintWriter(writer));
|
||||
builder.append(writer);
|
||||
}
|
||||
|
||||
String message = builder.toString();
|
||||
Object parameters[] = record.getParameters();
|
||||
if (parameters == null || parameters.length == 0)
|
||||
return message;
|
||||
if (
|
||||
message.indexOf("{0") >= 0
|
||||
|| message.indexOf("{1") >= 0
|
||||
|| message.indexOf("{2") >= 0
|
||||
|| message.indexOf("{3") >= 0
|
||||
)
|
||||
return java.text.MessageFormat.format(message, parameters);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
23
java/io/eiren/yaml/YamlException.java
Normal file
23
java/io/eiren/yaml/YamlException.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package io.eiren.yaml;
|
||||
|
||||
/**
|
||||
* Configuration exception.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class YamlException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -2442886939908724203L;
|
||||
|
||||
public YamlException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public YamlException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public YamlException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
149
java/io/eiren/yaml/YamlFile.java
Normal file
149
java/io/eiren/yaml/YamlFile.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package io.eiren.yaml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.BaseConstructor;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
import org.yaml.snakeyaml.reader.UnicodeReader;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
|
||||
/**
|
||||
* YAML configuration loader. To use this class, construct it with path to a
|
||||
* file and call its load() method. For specifying node paths in the various
|
||||
* get*() methods, they support SK's path notation, allowing you to select child
|
||||
* nodes by delimiting node names with periods.
|
||||
*
|
||||
* <p>
|
||||
* For example, given the following configuration file:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* members:
|
||||
* - Hollie
|
||||
* - Jason
|
||||
* - Bobo
|
||||
* - Aya
|
||||
* - Tetsu
|
||||
* worldguard:
|
||||
* fire:
|
||||
* spread: false
|
||||
* blocks: [cloth, rock, glass]
|
||||
* sturmeh:
|
||||
* cool: false
|
||||
* eats:
|
||||
* babies: true
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Calling code could access sturmeh's baby eating state by using
|
||||
* <code>getBoolean("sturmeh.eats.babies", false)</code>. For lists, there are
|
||||
* methods such as <code>getStringList</code> that will return a type safe list.
|
||||
*
|
||||
* <p>
|
||||
* This class is currently incomplete. It is not yet possible to get a node.
|
||||
* </p>
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class YamlFile extends YamlNode {
|
||||
|
||||
private static Representer defaultRepresenter = new Representer();
|
||||
|
||||
private Representer representer = defaultRepresenter;
|
||||
private BaseConstructor constructor = new SafeConstructor();
|
||||
private DumperOptions options = new DumperOptions();
|
||||
|
||||
{
|
||||
options.setIndent(4);
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.AUTO);
|
||||
}
|
||||
|
||||
public YamlFile(Map<String, Object> rootMap) {
|
||||
super(rootMap);
|
||||
}
|
||||
|
||||
public YamlFile() {
|
||||
super(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public DumperOptions getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setRepresenter(Representer representer) {
|
||||
this.representer = representer;
|
||||
}
|
||||
|
||||
public void setBaseConstructor(BaseConstructor constr) {
|
||||
this.constructor = constr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration file. All errors are thrown away.
|
||||
*
|
||||
* @throws YamlException
|
||||
*/
|
||||
public void load(InputStream input) throws YamlException {
|
||||
try {
|
||||
Yaml yaml = new Yaml(constructor, representer, options);
|
||||
read(yaml.load(new UnicodeReader(input)));
|
||||
} catch (YamlException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new YamlException("Exception while parsing yaml", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the configuration to disk. All errors are clobbered.
|
||||
*
|
||||
* @return true if it was successful
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public void save(OutputStream output) {
|
||||
Yaml yaml = new Yaml(constructor, representer, options);
|
||||
try {
|
||||
yaml.dump(root, new OutputStreamWriter(output, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void read(Object input) throws YamlException {
|
||||
try {
|
||||
root = (Map<String, Object>) (input == null ? new HashMap<String, Object>() : input);
|
||||
} catch (ClassCastException e) {
|
||||
throw new YamlException(
|
||||
"Root document must be an key-value structure, recieved: " + input
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns an empty ConfigurationNode for using as a default in
|
||||
* methods that select a node from a node list.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static YamlNode getEmptyNode() {
|
||||
return new YamlNode(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public static YamlNode getEmptySortedNode() {
|
||||
return new YamlNode(new TreeMap<String, Object>());
|
||||
}
|
||||
|
||||
public static void setDefaultRepresenter(Representer r) {
|
||||
defaultRepresenter = r;
|
||||
}
|
||||
}
|
||||
642
java/io/eiren/yaml/YamlNode.java
Normal file
642
java/io/eiren/yaml/YamlNode.java
Normal file
@@ -0,0 +1,642 @@
|
||||
package io.eiren.yaml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.eiren.util.Util;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a configuration node.
|
||||
*
|
||||
* @author sk89q
|
||||
*/
|
||||
public class YamlNode {
|
||||
|
||||
public Map<String, Object> root;
|
||||
|
||||
public YamlNode(Map<String, Object> root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public Object getProperty(String path) {
|
||||
return getProperty(path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property at a location. This will either return an Object or null,
|
||||
* with null meaning that no configuration value exists at that location.
|
||||
* This could potentially return a default value (not yet implemented) as
|
||||
* defined by a plugin, if this is a plugin-tied configuration.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @return object or null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getProperty(String path, boolean allowDot) {
|
||||
if (allowDot || !path.contains(".")) {
|
||||
Object val = root.get(path);
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
String[] parts = path.split("\\.");
|
||||
Map<String, Object> node = root;
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
Object o = node.get(parts[i]);
|
||||
if (o == null)
|
||||
return null;
|
||||
|
||||
if (i == parts.length - 1)
|
||||
return o;
|
||||
|
||||
try {
|
||||
node = (Map<String, Object>) o;
|
||||
} catch (ClassCastException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setProperty(String path, Object value) {
|
||||
setProperty(path, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property at a location. This will override existing configuration
|
||||
* data to have it conform to key/value mappings.
|
||||
*
|
||||
* @param path
|
||||
* @param value
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setProperty(String path, Object value, boolean allowDot) {
|
||||
if (value instanceof YamlNode)
|
||||
value = ((YamlNode) value).root;
|
||||
if (allowDot || !path.contains(".")) {
|
||||
root.put(path, value);
|
||||
return;
|
||||
}
|
||||
|
||||
String[] parts = path.split("\\.");
|
||||
Map<String, Object> node = root;
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
Object o = node.get(parts[i]);
|
||||
|
||||
// Found our target!
|
||||
if (i == parts.length - 1) {
|
||||
node.put(parts[i], value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (o == null || !(o instanceof Map)) {
|
||||
// This will override existing configuration data!
|
||||
o = new HashMap<String, Object>();
|
||||
node.put(parts[i], o);
|
||||
}
|
||||
|
||||
node = (Map<String, Object>) o;
|
||||
}
|
||||
}
|
||||
|
||||
public void merge(YamlNode node) {
|
||||
merge(node.root);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void merge(Map<String, Object> map) {
|
||||
Iterator<Entry<String, Object>> iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<String, Object> e = iterator.next();
|
||||
if (e.getValue() == null)
|
||||
continue;
|
||||
Object old = root.get(e.getKey());
|
||||
if (old == null) {
|
||||
root.put(e.getKey(), e.getValue());
|
||||
} else if (old instanceof Map) {
|
||||
if (!(e.getValue() instanceof Map)) {
|
||||
root.put(e.getKey(), e.getValue());
|
||||
} else {
|
||||
new YamlNode((Map<String, Object>) old)
|
||||
.merge((Map<String, Object>) e.getValue());
|
||||
}
|
||||
} else if (old instanceof List) {
|
||||
if (!(e.getValue() instanceof List)) {
|
||||
root.put(e.getKey(), e.getValue());
|
||||
} else {
|
||||
((List) old).addAll((List) e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string at a location. This will either return an String or null,
|
||||
* with null meaning that no configuration value exists at that location. If
|
||||
* the object at the particular location is not actually a string, it will
|
||||
* be converted to its string representation.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @return string or null
|
||||
*/
|
||||
public String getString(String path) {
|
||||
Object o = getProperty(path);
|
||||
if (o == null)
|
||||
return null;
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string at a location. This will either return an String or the
|
||||
* default value. If the object at the particular location is not actually a
|
||||
* string, it will be converted to its string representation.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value
|
||||
* @return string or default
|
||||
*/
|
||||
public String getString(String path, String def) {
|
||||
String o = getString(path);
|
||||
if (o == null)
|
||||
return def;
|
||||
return o;
|
||||
}
|
||||
|
||||
public int getInt(String path, int def) {
|
||||
return getInt(path, def, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer at a location. This will either return an integer or the
|
||||
* default value. If the object at the particular location is not actually a
|
||||
* integer, the default value will be returned. However, other number types
|
||||
* will be casted to an integer.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value
|
||||
* @return int or default
|
||||
*/
|
||||
public int getInt(String path, int def, boolean allowDot) {
|
||||
Integer o = castInt(getProperty(path, allowDot));
|
||||
if (o == null)
|
||||
return def;
|
||||
else
|
||||
return o;
|
||||
}
|
||||
|
||||
public long getLong(String path, long def) {
|
||||
Long o = castLong(getProperty(path));
|
||||
if (o == null)
|
||||
return def;
|
||||
else
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a double at a location. This will either return an double or the
|
||||
* default value. If the object at the particular location is not actually a
|
||||
* double, the default value will be returned. However, other number types
|
||||
* will be casted to an double.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value
|
||||
* @return double or default
|
||||
*/
|
||||
public double getDouble(String path, double def) {
|
||||
Double o = castDouble(getProperty(path));
|
||||
if (o == null)
|
||||
return def;
|
||||
else
|
||||
return o;
|
||||
}
|
||||
|
||||
public float getFloat(String path, float def) {
|
||||
return getFloat(path, def, false);
|
||||
}
|
||||
|
||||
public float getFloat(String path, float def, boolean allowDot) {
|
||||
Float o = castFloat(getProperty(path, allowDot));
|
||||
if (o == null)
|
||||
return def;
|
||||
else
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean at a location. This will either return an boolean or the
|
||||
* default value. If the object at the particular location is not actually a
|
||||
* boolean, the default value will be returned.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value
|
||||
* @return boolean or default
|
||||
*/
|
||||
public boolean getBoolean(String path, boolean def) {
|
||||
Boolean o = castBoolean(getProperty(path));
|
||||
if (o == null) {
|
||||
return def;
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of keys at a location. If the map at the particular location
|
||||
* does not exist or it is not a map, null will be returned.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @return list of keys
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getKeys(String path) {
|
||||
if (path == null)
|
||||
return new ArrayList<String>(root.keySet());
|
||||
Object o = getProperty(path);
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Map) {
|
||||
return new ArrayList<String>(((Map<String, Object>) o).keySet());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of objects at a location. If the list is not defined, null
|
||||
* will be returned. The node must be an actual list.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @return boolean or default
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> getList(String path) {
|
||||
Object o = getProperty(path);
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof List) {
|
||||
return (List<Object>) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of strings. Non-valid entries will not be in the list. There
|
||||
* will be no null slots. If the list is not defined, the default will be
|
||||
* returned. 'null' can be passed for the default and an empty list will be
|
||||
* returned instead. If an item in the list is not a string, it will be
|
||||
* converted to a string. The node must be an actual list and not just a
|
||||
* string.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value or null for an empty list as default
|
||||
* @return list of strings
|
||||
*/
|
||||
public List<String> getStringList(String path, List<String> def) {
|
||||
List<Object> raw = getList(path);
|
||||
if (raw == null) {
|
||||
return def != null ? def : new ArrayList<String>(0);
|
||||
}
|
||||
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (Object o : raw) {
|
||||
if (o == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(o.toString());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of integers. Non-valid entries will not be in the list. There
|
||||
* will be no null slots. If the list is not defined, the default will be
|
||||
* returned. 'null' can be passed for the default and an empty list will be
|
||||
* returned instead. The node must be an actual list and not just an
|
||||
* integer.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value or null for an empty list as default
|
||||
* @return list of integers
|
||||
*/
|
||||
public List<Integer> getIntList(String path, List<Integer> def) {
|
||||
List<Object> raw = getList(path);
|
||||
if (raw == null) {
|
||||
return def != null ? def : new ArrayList<Integer>(0);
|
||||
}
|
||||
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
for (Object o : raw) {
|
||||
Integer i = castInt(o);
|
||||
if (i != null) {
|
||||
list.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of doubles. Non-valid entries will not be in the list. There
|
||||
* will be no null slots. If the list is not defined, the default will be
|
||||
* returned. 'null' can be passed for the default and an empty list will be
|
||||
* returned instead. The node must be an actual list and cannot be just a
|
||||
* double.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value or null for an empty list as default
|
||||
* @return list of integers
|
||||
*/
|
||||
public List<Double> getDoubleList(String path, List<Double> def) {
|
||||
List<Object> raw = getList(path);
|
||||
if (raw == null) {
|
||||
return def != null ? def : new ArrayList<Double>(0);
|
||||
}
|
||||
|
||||
List<Double> list = new ArrayList<Double>();
|
||||
for (Object o : raw) {
|
||||
Double i = castDouble(o);
|
||||
if (i != null) {
|
||||
list.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of booleans. Non-valid entries will not be in the list. There
|
||||
* will be no null slots. If the list is not defined, the default will be
|
||||
* returned. 'null' can be passed for the default and an empty list will be
|
||||
* returned instead. The node must be an actual list and cannot be just a
|
||||
* boolean,
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value or null for an empty list as default
|
||||
* @return list of integers
|
||||
*/
|
||||
public List<Boolean> getBooleanList(String path, List<Boolean> def) {
|
||||
List<Object> raw = getList(path);
|
||||
if (raw == null) {
|
||||
return def != null ? def : new ArrayList<Boolean>(0);
|
||||
}
|
||||
|
||||
List<Boolean> list = new ArrayList<Boolean>();
|
||||
for (Object o : raw) {
|
||||
Boolean tetsu = castBoolean(o);
|
||||
if (tetsu != null) {
|
||||
list.add(tetsu);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of nodes. Non-valid entries will not be in the list. There
|
||||
* will be no null slots. If the list is not defined, the default will be
|
||||
* returned. 'null' can be passed for the default and an empty list will be
|
||||
* returned instead. The node must be an actual node and cannot be just a
|
||||
* boolean,
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @param def default value or null for an empty list as default
|
||||
* @return list of integers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<YamlNode> getNodeList(String path, List<YamlNode> def) {
|
||||
List<Object> raw = getList(path);
|
||||
if (raw == null) {
|
||||
return def != null ? def : new ArrayList<YamlNode>(0);
|
||||
}
|
||||
|
||||
List<YamlNode> list = new ArrayList<YamlNode>();
|
||||
for (Object o : raw) {
|
||||
if (o instanceof Map) {
|
||||
list.add(new YamlNode((Map<String, Object>) o));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public YamlNode getNode(String path) {
|
||||
return getNode(path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a configuration node at a path. If the node doesn't exist or the path
|
||||
* does not lead to a node, null will be returned. A node has key/value
|
||||
* mappings.
|
||||
*
|
||||
* @param path
|
||||
* @return node or null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public YamlNode getNode(String path, boolean allowDot) {
|
||||
Object raw = getProperty(path, allowDot);
|
||||
if (raw instanceof Map) {
|
||||
return new YamlNode((Map<String, Object>) raw);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of nodes at a location. If the map at the particular location
|
||||
* does not exist or it is not a map, null will be returned.
|
||||
*
|
||||
* @param path path to node (dot notation)
|
||||
* @return map of nodes
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, YamlNode> getNodes(String path) {
|
||||
Object o = getProperty(path);
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Map) {
|
||||
Map<String, YamlNode> nodes = new HashMap<String, YamlNode>();
|
||||
|
||||
for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) {
|
||||
if (entry.getValue() instanceof Map) {
|
||||
nodes.put(entry.getKey(), new YamlNode((Map<String, Object>) entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a value to an integer. May return null.
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
private static Integer castInt(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Byte) {
|
||||
return (int) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (Integer) o;
|
||||
} else if (o instanceof Double) {
|
||||
return (int) (double) (Double) o;
|
||||
} else if (o instanceof Float) {
|
||||
return (int) (float) (Float) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (int) (long) (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Long castLong(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Byte) {
|
||||
return (long) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (long) (int) (Integer) o;
|
||||
} else if (o instanceof Double) {
|
||||
return (long) (double) (Double) o;
|
||||
} else if (o instanceof Float) {
|
||||
return (long) (float) (Float) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a value to a double. May return null.
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
private static Double castDouble(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Float) {
|
||||
return (double) (Float) o;
|
||||
} else if (o instanceof Double) {
|
||||
return (Double) o;
|
||||
} else if (o instanceof Byte) {
|
||||
return (double) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (double) (Integer) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (double) (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Float castFloat(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Float) {
|
||||
return (Float) o;
|
||||
} else if (o instanceof Double) {
|
||||
return ((Double) o).floatValue();
|
||||
} else if (o instanceof Byte) {
|
||||
return (float) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (float) (Integer) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (float) (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts a value to a boolean. May return null.
|
||||
*
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
private static Boolean castBoolean(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Boolean) {
|
||||
return (Boolean) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeProperty(String path) {
|
||||
removeProperty(path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the property at a location. This will override existing
|
||||
* configuration data to have it conform to key/value mappings.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeProperty(String path, boolean allowDot) {
|
||||
if (allowDot || !path.contains(".")) {
|
||||
root.remove(path);
|
||||
return;
|
||||
}
|
||||
|
||||
String[] parts = path.split("\\.");
|
||||
Map<String, Object> node = root;
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
Object o = node.get(parts[i]);
|
||||
|
||||
// Found our target!
|
||||
if (i == parts.length - 1) {
|
||||
node.remove(parts[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
node = (Map<String, Object>) o;
|
||||
if (node == null)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void fullDump(Map<String, Object> target, String prefix) {
|
||||
Iterator<Entry<String, Object>> i = root.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Entry<String, Object> e = i.next();
|
||||
if (e.getValue() instanceof Map)
|
||||
new YamlNode((Map<String, Object>) e.getValue())
|
||||
.fullDump(target, prefix + e.getKey() + ".");
|
||||
else
|
||||
target.put(prefix + e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> fullDump() {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
fullDump(map, "");
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Util.toString(root);
|
||||
}
|
||||
}
|
||||
880
java/org/json/JSONArray.java
Normal file
880
java/org/json/JSONArray.java
Normal file
@@ -0,0 +1,880 @@
|
||||
package org.json;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A JSONArray is an ordered sequence of values. Its external text form is a
|
||||
* string wrapped in square brackets with commas separating the values. The
|
||||
* internal form is an object having <code>get</code> and <code>opt</code>
|
||||
* methods for accessing the values by index, and <code>put</code> methods for
|
||||
* adding or replacing values. The values can be any of these types:
|
||||
* <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
|
||||
* <code>Number</code>, <code>String</code>, or the
|
||||
* <code>JSONObject.NULL object</code>.
|
||||
* <p>
|
||||
* The constructor can convert a JSON text into a Java object. The
|
||||
* <code>toString</code> method converts to JSON text.
|
||||
* <p>
|
||||
* A <code>get</code> method returns a value if one can be found, and throws an
|
||||
* exception if one cannot be found. An <code>opt</code> method returns a
|
||||
* default value instead of throwing an exception, and so is useful for
|
||||
* obtaining optional values.
|
||||
* <p>
|
||||
* The generic <code>get()</code> and <code>opt()</code> methods return an
|
||||
* object which you can cast or query for type. There are also typed
|
||||
* <code>get</code> and <code>opt</code> methods that do type checking and type
|
||||
* coercion for you.
|
||||
* <p>
|
||||
* The texts produced by the <code>toString</code> methods strictly conform to
|
||||
* JSON syntax rules. The constructors are more forgiving in the texts they will
|
||||
* accept:
|
||||
* <ul>
|
||||
* <li>An extra <code>,</code> <small>(comma)</small> may appear just
|
||||
* before the closing bracket.</li>
|
||||
* <li>The <code>null</code> value will be inserted when there is <code>,</code>
|
||||
* <small>(comma)</small> elision.</li>
|
||||
* <li>Strings may be quoted with <code>'</code> <small>(single
|
||||
* quote)</small>.</li>
|
||||
* <li>Strings do not need to be quoted at all if they do not begin with a quote
|
||||
* or single quote, and if they do not contain leading or trailing spaces, and
|
||||
* if they do not contain any of these characters:
|
||||
* <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
|
||||
* if they are not the reserved words <code>true</code>, <code>false</code>, or
|
||||
* <code>null</code>.</li>
|
||||
* <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
|
||||
* well as by <code>,</code> <small>(comma)</small>.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2012-04-20
|
||||
*/
|
||||
public class JSONArray {
|
||||
|
||||
/**
|
||||
* The arrayList where the JSONArray's properties are kept.
|
||||
*/
|
||||
private final ArrayList<Object> myArrayList;
|
||||
|
||||
/**
|
||||
* Construct an empty JSONArray.
|
||||
*/
|
||||
public JSONArray() {
|
||||
this.myArrayList = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
public JSONArray(int initialLength) {
|
||||
this.myArrayList = new ArrayList<Object>(initialLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a JSONTokener.
|
||||
*
|
||||
* @param x A JSONTokener
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(JSONTokener x) throws JSONException {
|
||||
this();
|
||||
if (x.nextClean() != '[') {
|
||||
throw x.syntaxError("A JSONArray text must start with '['");
|
||||
}
|
||||
if (x.nextClean() != ']') {
|
||||
x.back();
|
||||
for (;;) {
|
||||
if (x.nextClean() == ',') {
|
||||
x.back();
|
||||
this.myArrayList.add(JSONObject.NULL);
|
||||
} else {
|
||||
x.back();
|
||||
this.myArrayList.add(x.nextValue());
|
||||
}
|
||||
switch (x.nextClean()) {
|
||||
case ';':
|
||||
case ',':
|
||||
if (x.nextClean() == ']') {
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
break;
|
||||
case ']':
|
||||
return;
|
||||
default:
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a source JSON text.
|
||||
*
|
||||
* @param source A string that begins with <code>[</code> <small>(left
|
||||
* bracket)</small> and ends with <code>]</code> <small>(right
|
||||
* bracket)</small>.
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a Collection.
|
||||
*
|
||||
* @param collection A Collection.
|
||||
*/
|
||||
public JSONArray(Collection<Object> collection) {
|
||||
this.myArrayList = new ArrayList<Object>();
|
||||
if (collection != null) {
|
||||
Iterator<Object> iter = collection.iterator();
|
||||
while (iter.hasNext()) {
|
||||
this.myArrayList.add(JSONObject.wrap(iter.next()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from an array
|
||||
*
|
||||
* @throws JSONException If not an array.
|
||||
*/
|
||||
public JSONArray(Object array) {
|
||||
this();
|
||||
if (array.getClass().isArray()) {
|
||||
int length = Array.getLength(array);
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
this.put(JSONObject.wrap(Array.get(array, i)));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"JSONArray initial value should be a string or collection or array."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return An object value.
|
||||
* @throws JSONException If there is no value for the index.
|
||||
*/
|
||||
public Object get(int index) throws JSONException {
|
||||
Object object = this.opt(index);
|
||||
if (object == null) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boolean value associated with an index. The string values "true"
|
||||
* and "false" are converted to boolean.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
* @throws JSONException If there is no value for the index or if the value
|
||||
* is not convertible to boolean.
|
||||
*/
|
||||
public boolean getBoolean(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if (
|
||||
object.equals(Boolean.FALSE)
|
||||
|| (object instanceof String && ((String) object).equalsIgnoreCase("false"))
|
||||
) {
|
||||
return false;
|
||||
} else if (
|
||||
object.equals(Boolean.TRUE)
|
||||
|| (object instanceof String && ((String) object).equalsIgnoreCase("true"))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a boolean.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the double value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot be
|
||||
* converted to a number.
|
||||
*/
|
||||
public double getDouble(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number
|
||||
? ((Number) object).doubleValue()
|
||||
: Double.parseDouble((String) object);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the int value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value is not a
|
||||
* number.
|
||||
*/
|
||||
public int getInt(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number
|
||||
? ((Number) object).intValue()
|
||||
: Integer.parseInt((String) object);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONArray associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONArray value.
|
||||
* @throws JSONException If there is no value for the index. or if the value
|
||||
* is not a JSONArray
|
||||
*/
|
||||
public JSONArray getJSONArray(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if (object instanceof JSONArray) {
|
||||
return (JSONArray) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONObject associated with an index.
|
||||
*
|
||||
* @param index subscript
|
||||
* @return A JSONObject value.
|
||||
* @throws JSONException If there is no value for the index or if the value
|
||||
* is not a JSONObject
|
||||
*/
|
||||
public JSONObject getJSONObject(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if (object instanceof JSONObject) {
|
||||
return (JSONObject) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the long value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot be
|
||||
* converted to a number.
|
||||
*/
|
||||
public long getLong(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
try {
|
||||
return object instanceof Number
|
||||
? ((Number) object).longValue()
|
||||
: Long.parseLong((String) object);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A string value.
|
||||
* @throws JSONException If there is no string value for the index.
|
||||
*/
|
||||
public String getString(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if (object instanceof String) {
|
||||
return (String) object;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] not a string.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the value is null.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return true if the value at the index is null, or if there is no value.
|
||||
*/
|
||||
public boolean isNull(int index) {
|
||||
return JSONObject.NULL.equals(this.opt(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a string from the contents of this JSONArray. The
|
||||
* <code>separator</code> string is inserted between each element. Warning:
|
||||
* This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @param separator A string that will be inserted between the elements.
|
||||
* @return a string.
|
||||
* @throws JSONException If the array contains an invalid number.
|
||||
*/
|
||||
public String join(String separator) throws JSONException {
|
||||
int len = this.length();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of elements in the JSONArray, included nulls.
|
||||
*
|
||||
* @return The length (or size).
|
||||
*/
|
||||
public int length() {
|
||||
return this.myArrayList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional object value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return An object value, or null if there is no object at that index.
|
||||
*/
|
||||
public Object opt(int index) {
|
||||
return (index < 0 || index >= this.length()) ? null : this.myArrayList.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index. It returns false
|
||||
* if there is no value at that index, or if the value is not Boolean.TRUE
|
||||
* or the String "true".
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index) {
|
||||
return this.optBoolean(index, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index. It returns the
|
||||
* defaultValue if there is no value at that index or if it is not a Boolean
|
||||
* or the String "true" or "false" (case insensitive).
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue A boolean default.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index, boolean defaultValue) {
|
||||
try {
|
||||
return this.getBoolean(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index. NaN is returned
|
||||
* if there is no value for the index, or if the value is not a number and
|
||||
* cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index) {
|
||||
return this.optDouble(index, Double.NaN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index. The defaultValue
|
||||
* is returned if there is no value for the index, or if the value is not a
|
||||
* number and cannot be converted to a number.
|
||||
*
|
||||
* @param index subscript
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index, double defaultValue) {
|
||||
try {
|
||||
return this.getDouble(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index. Zero is returned if
|
||||
* there is no value for the index, or if the value is not a number and
|
||||
* cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index) {
|
||||
return this.optInt(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index. The defaultValue is
|
||||
* returned if there is no value for the index, or if the value is not a
|
||||
* number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index, int defaultValue) {
|
||||
try {
|
||||
return this.getInt(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONArray associated with an index.
|
||||
*
|
||||
* @param index subscript
|
||||
* @return A JSONArray value, or null if the index has no value, or if the
|
||||
* value is not a JSONArray.
|
||||
*/
|
||||
public JSONArray optJSONArray(int index) {
|
||||
Object o = this.opt(index);
|
||||
return o instanceof JSONArray ? (JSONArray) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONObject associated with an index. Null is returned if
|
||||
* the key is not found, or null if the index has no value, or if the value
|
||||
* is not a JSONObject.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONObject value.
|
||||
*/
|
||||
public JSONObject optJSONObject(int index) {
|
||||
Object o = this.opt(index);
|
||||
return o instanceof JSONObject ? (JSONObject) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index. Zero is returned if
|
||||
* there is no value for the index, or if the value is not a number and
|
||||
* cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index) {
|
||||
return this.optLong(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index. The defaultValue is
|
||||
* returned if there is no value for the index, or if the value is not a
|
||||
* number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index, long defaultValue) {
|
||||
try {
|
||||
return this.getLong(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string value associated with an index. It returns an
|
||||
* empty string if there is no value at that index. If the value is not a
|
||||
* string and is not null, then it is coverted to a string.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index) {
|
||||
return this.optString(index, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string associated with an index. The defaultValue is
|
||||
* returned if the key is not found.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index, String defaultValue) {
|
||||
Object object = this.opt(index);
|
||||
return JSONObject.NULL.equals(object) ? defaultValue : object.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a boolean value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(boolean value) {
|
||||
this.put(value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONArray which
|
||||
* is produced from a Collection.
|
||||
*
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Collection<Object> value) {
|
||||
this.put(new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A double value.
|
||||
* @throws JSONException if the value is not finite.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(double value) throws JSONException {
|
||||
Double d = new Double(value);
|
||||
JSONObject.testValidity(d);
|
||||
this.put(d);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an int value. This increases the array's length by one.
|
||||
*
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(int value) {
|
||||
this.put(new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an long value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(long value) {
|
||||
this.put(new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONObject which
|
||||
* is produced from a Map.
|
||||
*
|
||||
* @param value A Map value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Map<Object, Object> value) {
|
||||
this.put(new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an object value. This increases the array's length by one.
|
||||
*
|
||||
* @param value An object value. The value should be a Boolean, Double,
|
||||
* Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL
|
||||
* object.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Object value) {
|
||||
this.myArrayList.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a boolean value in the JSONArray. If the index is greater
|
||||
* than the length of the JSONArray, then null elements will be added as
|
||||
* necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, boolean value) throws JSONException {
|
||||
this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONArray which
|
||||
* is produced from a Collection.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is not
|
||||
* finite.
|
||||
*/
|
||||
public JSONArray put(int index, Collection<Object> value) throws JSONException {
|
||||
this.put(index, new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a double value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad it
|
||||
* out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A double value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is not
|
||||
* finite.
|
||||
*/
|
||||
public JSONArray put(int index, double value) throws JSONException {
|
||||
this.put(index, new Double(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an int value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad it
|
||||
* out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, int value) throws JSONException {
|
||||
this.put(index, new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a long value. If the index is greater than the length of
|
||||
* the JSONArray, then null elements will be added as necessary to pad it
|
||||
* out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, long value) throws JSONException {
|
||||
this.put(index, new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONObject that
|
||||
* is produced from a Map.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value The Map value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is an
|
||||
* invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Map<Object, Object> value) throws JSONException {
|
||||
this.put(index, new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an object value in the JSONArray. If the index is greater
|
||||
* than the length of the JSONArray, then null elements will be added as
|
||||
* necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value The value to put into the array. The value should be a
|
||||
* Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
|
||||
* JSONObject.NULL object.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is an
|
||||
* invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Object value) throws JSONException {
|
||||
JSONObject.testValidity(value);
|
||||
if (index < 0) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
if (index < this.length()) {
|
||||
this.myArrayList.set(index, value);
|
||||
} else {
|
||||
while (index != this.length()) {
|
||||
this.put(JSONObject.NULL);
|
||||
}
|
||||
this.put(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an index and close the hole.
|
||||
*
|
||||
* @param index The index of the element to be removed.
|
||||
* @return The value that was associated with the index, or null if there
|
||||
* was no value.
|
||||
*/
|
||||
public Object remove(int index) {
|
||||
Object o = this.opt(index);
|
||||
this.myArrayList.remove(index);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject by combining a JSONArray of names with the values of
|
||||
* this JSONArray.
|
||||
*
|
||||
* @param names A JSONArray containing a list of key strings. These will be
|
||||
* paired with the values.
|
||||
* @return A JSONObject, or null if there are no names or if this JSONArray
|
||||
* has no values.
|
||||
* @throws JSONException If any of the names are null.
|
||||
*/
|
||||
public JSONObject toJSONObject(JSONArray names) throws JSONException {
|
||||
if (names == null || names.length() == 0 || this.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONObject jo = new JSONObject();
|
||||
for (int i = 0; i < names.length(); i += 1) {
|
||||
jo.put(names.getString(i), this.opt(i));
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSON text of this JSONArray. For compactness, no unnecessary
|
||||
* whitespace is added. If it is not possible to produce a syntactically
|
||||
* correct JSON text then null will be returned instead. This could occur if
|
||||
* the array contains an invalid number.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return a printable, displayable, transmittable representation of the
|
||||
* array.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return '[' + this.join(",") + ']';
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a prettyprinted JSON text of this JSONArray. Warning: This method
|
||||
* assumes that the data structure is acyclical.
|
||||
*
|
||||
* @param indentFactor The number of spaces to add to each level of
|
||||
* indentation.
|
||||
* @return a printable, displayable, transmittable representation of the
|
||||
* object, beginning with <code>[</code> <small>(left bracket)</small>
|
||||
* and ending with <code>]</code> <small>(right bracket)</small>.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public String toString(int indentFactor) throws JSONException {
|
||||
StringWriter sw = new StringWriter();
|
||||
synchronized (sw.getBuffer()) {
|
||||
return this.write(sw, indentFactor, 0).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the JSONArray as JSON text to a writer. For
|
||||
* compactness, no whitespace is added.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return The writer.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Writer write(Writer writer) throws JSONException {
|
||||
return this.write(writer, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the JSONArray as JSON text to a writer. For
|
||||
* compactness, no whitespace is added.
|
||||
* <p>
|
||||
* Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @param indentFactor The number of spaces to add to each level of
|
||||
* indentation.
|
||||
* @param indent The indention of the top level.
|
||||
* @return The writer.
|
||||
* @throws JSONException
|
||||
*/
|
||||
Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
|
||||
try {
|
||||
boolean commanate = false;
|
||||
int length = this.length();
|
||||
writer.write('[');
|
||||
|
||||
if (length == 1) {
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(0), indentFactor, indent);
|
||||
} else if (length != 0) {
|
||||
final int newindent = indent + indentFactor;
|
||||
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
if (commanate) {
|
||||
writer.write(',');
|
||||
}
|
||||
if (indentFactor > 0) {
|
||||
writer.write('\n');
|
||||
}
|
||||
JSONObject.indent(writer, newindent);
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(i), indentFactor, newindent);
|
||||
commanate = true;
|
||||
}
|
||||
if (indentFactor > 0) {
|
||||
writer.write('\n');
|
||||
}
|
||||
JSONObject.indent(writer, indent);
|
||||
}
|
||||
writer.write(']');
|
||||
return writer;
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
java/org/json/JSONException.java
Normal file
26
java/org/json/JSONException.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.json;
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes when things are amiss.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2010-12-24
|
||||
*/
|
||||
public class JSONException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
*
|
||||
* @param message Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONException(Throwable cause) {
|
||||
super(cause.getMessage());
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
1590
java/org/json/JSONObject.java
Normal file
1590
java/org/json/JSONObject.java
Normal file
File diff suppressed because it is too large
Load Diff
19
java/org/json/JSONString.java
Normal file
19
java/org/json/JSONString.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.json;
|
||||
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code>
|
||||
* method so that a class can change the behavior of
|
||||
* <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, and
|
||||
* <code>JSONWriter.value(</code>Object<code>)</code>. The
|
||||
* <code>toJSONString</code> method will be used instead of the default behavior
|
||||
* of using the Object's <code>toString()</code> method and quoting the result.
|
||||
*/
|
||||
public interface JSONString {
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own
|
||||
* JSON serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
||||
434
java/org/json/JSONTokener.java
Normal file
434
java/org/json/JSONTokener.java
Normal file
@@ -0,0 +1,434 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from
|
||||
* it. It is used by the JSONObject and JSONArray constructors to parse JSON
|
||||
* source strings.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2012-02-16
|
||||
*/
|
||||
public class JSONTokener {
|
||||
|
||||
private long character;
|
||||
private boolean eof;
|
||||
private long index;
|
||||
private long line;
|
||||
private char previous;
|
||||
private Reader reader;
|
||||
private boolean usePrevious;
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader.
|
||||
*
|
||||
* @param reader A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader) {
|
||||
this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
|
||||
this.eof = false;
|
||||
this.usePrevious = false;
|
||||
this.previous = 0;
|
||||
this.index = 0;
|
||||
this.character = 1;
|
||||
this.line = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from an InputStream.
|
||||
*/
|
||||
public JSONTokener(InputStream inputStream) throws JSONException {
|
||||
this(new InputStreamReader(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s A source string.
|
||||
*/
|
||||
public JSONTokener(String s) {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability, so
|
||||
* that you can test for a digit or letter before attempting to parse the
|
||||
* next number or identifier.
|
||||
*/
|
||||
public void back() throws JSONException {
|
||||
if (this.usePrevious || this.index <= 0) {
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
this.index -= 1;
|
||||
this.character -= 1;
|
||||
this.usePrevious = true;
|
||||
this.eof = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
*
|
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
||||
* between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean end() {
|
||||
return this.eof && !this.usePrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next() can
|
||||
* consume.
|
||||
*
|
||||
* @return true if not yet at the end of the source.
|
||||
*/
|
||||
public boolean more() throws JSONException {
|
||||
this.next();
|
||||
if (this.end()) {
|
||||
return false;
|
||||
}
|
||||
this.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
*/
|
||||
public char next() throws JSONException {
|
||||
int c;
|
||||
if (this.usePrevious) {
|
||||
this.usePrevious = false;
|
||||
c = this.previous;
|
||||
} else {
|
||||
try {
|
||||
c = this.reader.read();
|
||||
} catch (IOException exception) {
|
||||
throw new JSONException(exception);
|
||||
}
|
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.eof = true;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
this.index += 1;
|
||||
if (this.previous == '\r') {
|
||||
this.line += 1;
|
||||
this.character = c == '\n' ? 0 : 1;
|
||||
} else if (c == '\n') {
|
||||
this.line += 1;
|
||||
this.character = 0;
|
||||
} else {
|
||||
this.character += 1;
|
||||
}
|
||||
this.previous = (char) c;
|
||||
return this.previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified
|
||||
* character.
|
||||
*
|
||||
* @param c The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException {
|
||||
char n = this.next();
|
||||
if (n != c) {
|
||||
throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException Substring bounds error if there are not n
|
||||
* characters remaining in the source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] chars = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
while (pos < n) {
|
||||
chars[pos] = this.next();
|
||||
if (this.end()) {
|
||||
throw this.syntaxError("Substring bounds error");
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
*
|
||||
* @throws JSONException
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException {
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == 0 || c > ' ') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character. Backslash
|
||||
* processing is done. The formal JSON format does not allow strings in
|
||||
* single quotes, but an implementation is allowed to accept them.
|
||||
*
|
||||
* @param quote The quoting character, either <code>"</code>
|
||||
* <small>(double quote)</small> or <code>'</code>
|
||||
* <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
sb.append((char) Integer.parseInt(this.next(4), 16));
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the end of
|
||||
* line, whichever comes first.
|
||||
*
|
||||
* @param delimiter A delimiter character.
|
||||
* @return A string.
|
||||
*/
|
||||
public String nextTo(char delimiter) throws JSONException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
char c = this.next();
|
||||
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter
|
||||
* characters or the end of line, whichever comes first.
|
||||
*
|
||||
* @param delimiters A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (;;) {
|
||||
c = this.next();
|
||||
if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
this.back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
*
|
||||
* @throws JSONException If syntax error.
|
||||
*
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException {
|
||||
char c = this.nextClean();
|
||||
String string;
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
return this.nextString(c);
|
||||
case '{':
|
||||
this.back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
this.back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or null,
|
||||
* or it can be a number. An implementation (such as this one) is
|
||||
* allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||
sb.append(c);
|
||||
c = this.next();
|
||||
}
|
||||
this.back();
|
||||
|
||||
string = sb.toString().trim();
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character. If
|
||||
* the requested character is not found, no characters are skipped.
|
||||
*
|
||||
* @param to A character to skip to.
|
||||
* @return The requested character, or zero if the requested character is
|
||||
* not found.
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException {
|
||||
char c;
|
||||
try {
|
||||
long startIndex = this.index;
|
||||
long startCharacter = this.character;
|
||||
long startLine = this.line;
|
||||
this.reader.mark(1000000);
|
||||
do {
|
||||
c = this.next();
|
||||
if (c == 0) {
|
||||
this.reader.reset();
|
||||
this.index = startIndex;
|
||||
this.character = startCharacter;
|
||||
this.line = startLine;
|
||||
return c;
|
||||
}
|
||||
} while (c != to);
|
||||
} catch (IOException exc) {
|
||||
throw new JSONException(exc);
|
||||
}
|
||||
|
||||
this.back();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message) {
|
||||
return new JSONException(message + this.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at {index} [character {character} line {line}]"
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return " at " + this.index + " [character " + this.character + " line " + this.line + "]";
|
||||
}
|
||||
}
|
||||
57
java/org/json/JSONUtil.java
Normal file
57
java/org/json/JSONUtil.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package org.json;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class JSONUtil {
|
||||
|
||||
public static JSONObject toJSON(JSONEntry... entries) {
|
||||
return o(entries);
|
||||
}
|
||||
|
||||
public static JSONObject o(JSONEntry... entries) {
|
||||
JSONObject object = new JSONObject();
|
||||
for (int i = 0; i < entries.length; ++i) {
|
||||
JSONEntry e = entries[i];
|
||||
object.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public static JSONArray a(Object... values) {
|
||||
return new JSONArray(values);
|
||||
}
|
||||
|
||||
public static JSONEntry e(String k, Object v) {
|
||||
return new JSONEntry(k, v);
|
||||
}
|
||||
|
||||
public static class JSONEntry implements Entry<String, Object> {
|
||||
|
||||
private String key;
|
||||
private Object value;
|
||||
|
||||
public JSONEntry(String key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(Object value) {
|
||||
Object oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
1
protobuf_update.bat
Normal file
1
protobuf_update.bat
Normal file
@@ -0,0 +1 @@
|
||||
protoc --proto_path=../SlimeVR-OpenVR-Driver/src/bridge --java_out=./src/main/java ProtobufMessages.proto
|
||||
21
resources/LICENSE.txt
Normal file
21
resources/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Eiren Rain, SlimeVR
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1446
resources/ThirdPartyNotices.txt
Normal file
1446
resources/ThirdPartyNotices.txt
Normal file
File diff suppressed because it is too large
Load Diff
17
resources/firewall.bat
Normal file
17
resources/firewall.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
echo Installing firewall rules...
|
||||
|
||||
rem Discovery default port
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 35903 incoming" dir=in action=allow protocol=UDP localport=35903
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 35903 outgoing" dir=out action=allow protocol=UDP localport=35903
|
||||
|
||||
rem Rotational data default port
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 6969 incoming" dir=in action=allow protocol=UDP localport=6969
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 6969 outgoing" dir=out action=allow protocol=UDP localport=6969
|
||||
|
||||
rem WebSocket server default port
|
||||
netsh advfirewall firewall add rule name="SlimeVR TCP 21110 incoming" dir=in action=allow protocol=TCP localport=21110
|
||||
netsh advfirewall firewall add rule name="SlimeVR TCP 21110 outgoing" dir=out action=allow protocol=TCP localport=21110
|
||||
|
||||
echo Done!
|
||||
pause
|
||||
17
resources/firewall_uninstall.bat
Normal file
17
resources/firewall_uninstall.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
echo Uninstalling firewall rules...
|
||||
|
||||
rem Discovery defauly port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 35903 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 35903 outgoing"
|
||||
|
||||
rem Rotational data default port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 6969 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 6969 outgoing"
|
||||
|
||||
rem WebSocket server default port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR TCP 21110 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR TCP 21110 outgoing"
|
||||
|
||||
echo Done!
|
||||
pause
|
||||
19
resources/run.bat
Normal file
19
resources/run.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
setlocal enableextensions
|
||||
cd /d "%~dp0"
|
||||
|
||||
where java >nul 2>&1
|
||||
if %errorlevel% EQU 0 (
|
||||
java -Xmx512M -jar slimevr.jar
|
||||
) else (
|
||||
echo Java was not found in your system.
|
||||
echo.
|
||||
echo Either use SlimeVR Installer to install the server by following this link:
|
||||
echo https://github.com/SlimeVR/SlimeVR-Installer/releases/latest/download/slimevr_web_installer.exe
|
||||
echo.
|
||||
echo Or download Java 11 by following this link:
|
||||
echo https://adoptium.net/releases.html?variant=openjdk11^&jvmVariant=hotspot
|
||||
)
|
||||
if %errorlevel% NEQ 0 (
|
||||
pause
|
||||
)
|
||||
@@ -8,4 +8,8 @@
|
||||
*/
|
||||
|
||||
rootProject.name = 'SlimeVR Server'
|
||||
include('Slime Java Commons')
|
||||
include ':slime-java-commons'
|
||||
|
||||
|
||||
include ':solarxr-protocol'
|
||||
project(':solarxr-protocol').projectDir = new File('solarxr-protocol/protocol/java')
|
||||
|
||||
1
solarxr-protocol
Submodule
1
solarxr-protocol
Submodule
Submodule solarxr-protocol added at 86eb9aa6b5
400
spotless.xml
Normal file
400
spotless.xml
Normal file
@@ -0,0 +1,400 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="22">
|
||||
<profile kind="CodeFormatterProfile" name="Spotless" version="22">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="separate_lines_if_wrapped"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.javaFormatter" value="org.eclipse.jdt.core.defaultJavaFormatter"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
1072
src/main/java/com/jme3/math/FastMath.java
Normal file
1072
src/main/java/com/jme3/math/FastMath.java
Normal file
File diff suppressed because it is too large
Load Diff
1360
src/main/java/com/jme3/math/Matrix3f.java
Normal file
1360
src/main/java/com/jme3/math/Matrix3f.java
Normal file
File diff suppressed because it is too large
Load Diff
2275
src/main/java/com/jme3/math/Matrix4f.java
Normal file
2275
src/main/java/com/jme3/math/Matrix4f.java
Normal file
File diff suppressed because it is too large
Load Diff
1712
src/main/java/com/jme3/math/Quaternion.java
Normal file
1712
src/main/java/com/jme3/math/Quaternion.java
Normal file
File diff suppressed because it is too large
Load Diff
147
src/main/java/com/jme3/math/TempVars.java
Normal file
147
src/main/java/com/jme3/math/TempVars.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
/**
|
||||
* Temporary variables assigned to each thread. Engine classes may access these
|
||||
* temp variables with TempVars.get(), all retrieved TempVars instances must be
|
||||
* returned via TempVars.release(). This returns an available instance of the
|
||||
* TempVar class ensuring this particular instance is never used elsewhere in
|
||||
* the mean time.
|
||||
*/
|
||||
public class TempVars {
|
||||
|
||||
/**
|
||||
* Allow X instances of TempVars in a single thread.
|
||||
*/
|
||||
private static final int STACK_SIZE = 5;
|
||||
|
||||
/**
|
||||
* <code>TempVarsStack</code> contains a stack of TempVars. Every time
|
||||
* TempVars.get() is called, a new entry is added to the stack, and the
|
||||
* index incremented. When TempVars.release() is called, the entry is
|
||||
* checked against the current instance and then the index is decremented.
|
||||
*/
|
||||
private static class TempVarsStack {
|
||||
|
||||
int index = 0;
|
||||
TempVars[] tempVars = new TempVars[STACK_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* ThreadLocal to store a TempVarsStack for each thread. This ensures each
|
||||
* thread has a single TempVarsStack that is used only in method calls in
|
||||
* that thread.
|
||||
*/
|
||||
private static final ThreadLocal<TempVarsStack> varsLocal = new ThreadLocal<TempVarsStack>() {
|
||||
|
||||
@Override
|
||||
public TempVarsStack initialValue() {
|
||||
return new TempVarsStack();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This instance of TempVars has been retrieved but not released yet.
|
||||
*/
|
||||
private boolean isUsed = false;
|
||||
|
||||
private TempVars() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire an instance of the TempVar class. You have to release the
|
||||
* instance after use by calling the release() method. If more than
|
||||
* STACK_SIZE (currently 5) instances are requested in a single thread then
|
||||
* an ArrayIndexOutOfBoundsException will be thrown.
|
||||
*
|
||||
* @return A TempVar instance
|
||||
*/
|
||||
public static TempVars get() {
|
||||
TempVarsStack stack = varsLocal.get();
|
||||
|
||||
TempVars instance = stack.tempVars[stack.index];
|
||||
|
||||
if (instance == null) {
|
||||
// Create new
|
||||
instance = new TempVars();
|
||||
|
||||
// Put it in there
|
||||
stack.tempVars[stack.index] = instance;
|
||||
}
|
||||
|
||||
stack.index++;
|
||||
|
||||
instance.isUsed = true;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases this instance of TempVars. Once released, the contents of the
|
||||
* TempVars are undefined. The TempVars must be released in the opposite
|
||||
* order that they are retrieved, e.g. Acquiring vars1, then acquiring
|
||||
* vars2, vars2 MUST be released first otherwise an exception will be
|
||||
* thrown.
|
||||
*/
|
||||
public void release() {
|
||||
if (!isUsed) {
|
||||
throw new IllegalStateException("This instance of TempVars was already released!");
|
||||
}
|
||||
|
||||
isUsed = false;
|
||||
|
||||
TempVarsStack stack = varsLocal.get();
|
||||
|
||||
// Return it to the stack
|
||||
stack.index--;
|
||||
|
||||
// Check if it is actually there
|
||||
if (stack.tempVars[stack.index] != this) {
|
||||
throw new IllegalStateException(
|
||||
"An instance of TempVars has not been released in a called method!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General vectors.
|
||||
*/
|
||||
public final Vector3f vect1 = new Vector3f();
|
||||
public final Vector3f vect2 = new Vector3f();
|
||||
public final Vector3f vect3 = new Vector3f();
|
||||
/**
|
||||
* General matrices.
|
||||
*/
|
||||
public final Matrix4f tempMat4 = new Matrix4f();
|
||||
|
||||
public final float[] matrixWrite = new float[16];
|
||||
}
|
||||
399
src/main/java/com/jme3/math/Transform.java
Normal file
399
src/main/java/com/jme3/math/Transform.java
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
/**
|
||||
* Started Date: Jul 16, 2004<br>
|
||||
* <br>
|
||||
* Represents a translation, rotation and scale in one object.
|
||||
*
|
||||
* @author Jack Lindamood
|
||||
* @author Joshua Slack
|
||||
*/
|
||||
public final class Transform implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
|
||||
public static final Transform IDENTITY = new Transform();
|
||||
|
||||
private Quaternion rot = new Quaternion();
|
||||
private Vector3f translation = new Vector3f();
|
||||
private Vector3f scale = new Vector3f(1, 1, 1);
|
||||
|
||||
public Transform(Vector3f translation, Quaternion rot) {
|
||||
this.translation.set(translation);
|
||||
this.rot.set(rot);
|
||||
}
|
||||
|
||||
public Transform(Vector3f translation, Quaternion rot, Vector3f scale) {
|
||||
this(translation, rot);
|
||||
this.scale.set(scale);
|
||||
}
|
||||
|
||||
public Transform(Vector3f translation) {
|
||||
this(translation, Quaternion.IDENTITY);
|
||||
}
|
||||
|
||||
public Transform(Quaternion rot) {
|
||||
this(Vector3f.ZERO, rot);
|
||||
}
|
||||
|
||||
public Transform() {
|
||||
this(Vector3f.ZERO, Quaternion.IDENTITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this rotation to the given Quaternion value.
|
||||
*
|
||||
* @param rot The new rotation for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setRotation(Quaternion rot) {
|
||||
this.rot.set(rot);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this translation to the given value.
|
||||
*
|
||||
* @param trans The new translation for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setTranslation(Vector3f trans) {
|
||||
this.translation.set(trans);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the translation vector in this matrix.
|
||||
*
|
||||
* @return translation vector.
|
||||
*/
|
||||
public Vector3f getTranslation() {
|
||||
return translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this scale to the given value.
|
||||
*
|
||||
* @param scale The new scale for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(Vector3f scale) {
|
||||
this.scale.set(scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this scale to the given value.
|
||||
*
|
||||
* @param scale The new scale for this matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(float scale) {
|
||||
this.scale.set(scale, scale, scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scale vector in this matrix.
|
||||
*
|
||||
* @return scale vector.
|
||||
*/
|
||||
public Vector3f getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this translation value into the given vector3f. If trans is null,
|
||||
* a new vector3f is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param trans The store location for this matrix's translation.
|
||||
* @return The value of this matrix's translation.
|
||||
*/
|
||||
public Vector3f getTranslation(Vector3f trans) {
|
||||
if (trans == null)
|
||||
trans = new Vector3f();
|
||||
trans.set(this.translation);
|
||||
return trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this rotation value into the given Quaternion. If quat is null, a
|
||||
* new Quaternion is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param quat The store location for this matrix's rotation.
|
||||
* @return The value of this matrix's rotation.
|
||||
*/
|
||||
public Quaternion getRotation(Quaternion quat) {
|
||||
if (quat == null)
|
||||
quat = new Quaternion();
|
||||
quat.set(rot);
|
||||
return quat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rotation quaternion in this matrix.
|
||||
*
|
||||
* @return rotation quaternion.
|
||||
*/
|
||||
public Quaternion getRotation() {
|
||||
return rot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores this scale value into the given vector3f. If scale is null, a new
|
||||
* vector3f is created to hold the value. The value, once stored, is
|
||||
* returned.
|
||||
*
|
||||
* @param scale The store location for this matrix's scale.
|
||||
* @return The value of this matrix's scale.
|
||||
*/
|
||||
public Vector3f getScale(Vector3f scale) {
|
||||
if (scale == null)
|
||||
scale = new Vector3f();
|
||||
scale.set(this.scale);
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix to the interpolation between the first matrix and the
|
||||
* second by delta amount.
|
||||
*
|
||||
* @param t1 The begining transform.
|
||||
* @param t2 The ending transform.
|
||||
* @param delta An amount between 0 and 1 representing how far to
|
||||
* interpolate from t1 to t2.
|
||||
*/
|
||||
public void interpolateTransforms(Transform t1, Transform t2, float delta) {
|
||||
this.rot.slerp(t1.rot, t2.rot, delta);
|
||||
this.translation.interpolate(t1.translation, t2.translation, delta);
|
||||
this.scale.interpolate(t1.scale, t2.scale, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the values of this matrix acording to it's parent. Very similar
|
||||
* to the concept of Node/Spatial transforms.
|
||||
*
|
||||
* @param parent The parent matrix.
|
||||
* @return This matrix, after combining.
|
||||
*/
|
||||
public Transform combineWithParent(Transform parent) {
|
||||
scale.multLocal(parent.scale);
|
||||
// rot.multLocal(parent.rot);
|
||||
parent.rot.mult(rot, rot);
|
||||
|
||||
// This here, is evil code
|
||||
// parent
|
||||
// .rot
|
||||
// .multLocal(translation)
|
||||
// .multLocal(parent.scale)
|
||||
// .addLocal(parent.translation);
|
||||
|
||||
translation.multLocal(parent.scale);
|
||||
parent.rot
|
||||
.multLocal(translation)
|
||||
.addLocal(parent.translation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #combineWithParent(Transform)}, but assumes that rotation
|
||||
* is global, so it's not modified.
|
||||
*
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
public Transform combineWithParentGlobalRotation(Transform parent) {
|
||||
scale.multLocal(parent.scale);
|
||||
translation.multLocal(parent.scale);
|
||||
|
||||
parent.rot
|
||||
.multLocal(translation)
|
||||
.addLocal(parent.translation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix's translation to the given x,y,z values.
|
||||
*
|
||||
* @param x This matrix's new x translation.
|
||||
* @param y This matrix's new y translation.
|
||||
* @param z This matrix's new z translation.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setTranslation(float x, float y, float z) {
|
||||
translation.set(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix's scale to the given x,y,z values.
|
||||
*
|
||||
* @param x This matrix's new x scale.
|
||||
* @param y This matrix's new y scale.
|
||||
* @param z This matrix's new z scale.
|
||||
* @return this
|
||||
*/
|
||||
public Transform setScale(float x, float y, float z) {
|
||||
scale.set(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3f transformVector(final Vector3f in, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
|
||||
// multiply with scale first, then rotate, finally translate (cf.
|
||||
// Eberly)
|
||||
return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation);
|
||||
}
|
||||
|
||||
public Vector3f transformInverseVector(final Vector3f in, Vector3f store) {
|
||||
if (store == null)
|
||||
store = new Vector3f();
|
||||
|
||||
// The author of this code should look above and take the inverse of
|
||||
// that
|
||||
// But for some reason, they didnt ..
|
||||
// in.subtract(translation, store).divideLocal(scale);
|
||||
// rot.inverse().mult(store, store);
|
||||
|
||||
in.subtract(translation, store);
|
||||
rot.inverse().mult(store, store);
|
||||
store.divideLocal(scale);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1.
|
||||
*/
|
||||
public void loadIdentity() {
|
||||
translation.set(0, 0, 0);
|
||||
scale.set(1, 1, 1);
|
||||
rot.set(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()
|
||||
+ "[ "
|
||||
+ translation.x
|
||||
+ ", "
|
||||
+ translation.y
|
||||
+ ", "
|
||||
+ translation.z
|
||||
+ "]\n"
|
||||
+ "[ "
|
||||
+ rot.x
|
||||
+ ", "
|
||||
+ rot.y
|
||||
+ ", "
|
||||
+ rot.z
|
||||
+ ", "
|
||||
+ rot.w
|
||||
+ "]\n"
|
||||
+ "[ "
|
||||
+ scale.x
|
||||
+ " , "
|
||||
+ scale.y
|
||||
+ ", "
|
||||
+ scale.z
|
||||
+ "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this matrix to be equal to the given matrix.
|
||||
*
|
||||
* @param matrixQuat The matrix to be equal to.
|
||||
* @return this
|
||||
*/
|
||||
public Transform set(Transform matrixQuat) {
|
||||
this.translation.set(matrixQuat.translation);
|
||||
this.rot.set(matrixQuat.rot);
|
||||
this.scale.set(matrixQuat.scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((rot == null) ? 0 : rot.hashCode());
|
||||
result = prime * result + ((scale == null) ? 0 : scale.hashCode());
|
||||
result = prime * result + ((translation == null) ? 0 : translation.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Transform other = (Transform) obj;
|
||||
if (rot == null) {
|
||||
if (other.rot != null)
|
||||
return false;
|
||||
} else if (!rot.equals(other.rot))
|
||||
return false;
|
||||
if (scale == null) {
|
||||
if (other.scale != null)
|
||||
return false;
|
||||
} else if (!scale.equals(other.scale))
|
||||
return false;
|
||||
if (translation == null) {
|
||||
if (other.translation != null)
|
||||
return false;
|
||||
} else if (!translation.equals(other.translation))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transform clone() {
|
||||
try {
|
||||
Transform tq = (Transform) super.clone();
|
||||
tq.rot = rot.clone();
|
||||
tq.scale = scale.clone();
|
||||
tq.translation = translation.clone();
|
||||
return tq;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
718
src/main/java/com/jme3/math/Vector2f.java
Normal file
718
src/main/java/com/jme3/math/Vector2f.java
Normal file
@@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* <code>Vector2f</code> defines a Vector for a two float value vector.
|
||||
*
|
||||
* @author Mark Powell
|
||||
* @author Joshua Slack
|
||||
*/
|
||||
public final class Vector2f implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
private static final Logger logger = Logger.getLogger(Vector2f.class.getName());
|
||||
|
||||
public static final Vector2f ZERO = new Vector2f(0f, 0f);
|
||||
public static final Vector2f UNIT_XY = new Vector2f(1f, 1f);
|
||||
|
||||
/**
|
||||
* the x value of the vector.
|
||||
*/
|
||||
public float x;
|
||||
/**
|
||||
* the y value of the vector.
|
||||
*/
|
||||
public float y;
|
||||
|
||||
/**
|
||||
* Creates a Vector2f with the given initial x and y values.
|
||||
*
|
||||
* @param x The x value of this Vector2f.
|
||||
* @param y The y value of this Vector2f.
|
||||
*/
|
||||
public Vector2f(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector2f with x and y set to 0. Equivalent to Vector2f(0,0).
|
||||
*/
|
||||
public Vector2f() {
|
||||
x = y = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Vector2f that contains the passed vector's information
|
||||
*
|
||||
* @param vector2f The vector to copy
|
||||
*/
|
||||
public Vector2f(Vector2f vector2f) {
|
||||
this.x = vector2f.x;
|
||||
this.y = vector2f.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the x and y values of the vector
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector2f set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the x and y values of the vector from another vector
|
||||
*
|
||||
* @param vec the vector to copy from
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector2f set(Vector2f vec) {
|
||||
this.x = vec.x;
|
||||
this.y = vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>add</code> adds a provided vector to this vector creating a
|
||||
* resultant vector which is returned. If the provided vector is null, null
|
||||
* is returned.
|
||||
*
|
||||
* @param vec the vector to add to this.
|
||||
* @return the resultant vector.
|
||||
*/
|
||||
public Vector2f add(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return new Vector2f(x + vec.x, y + vec.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds a provided vector to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls. If the
|
||||
* provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to add to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f addLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds the provided values to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param addX value to add to x
|
||||
* @param addY value to add to y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f addLocal(float addX, float addY) {
|
||||
x += addX;
|
||||
y += addY;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>add</code> adds this vector by <code>vec</code> and stores the
|
||||
* result in <code>result</code>.
|
||||
*
|
||||
* @param vec The vector to add.
|
||||
* @param result The vector to store the result in.
|
||||
* @return The result vector, after adding.
|
||||
*/
|
||||
public Vector2f add(Vector2f vec, Vector2f result) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
if (result == null)
|
||||
result = new Vector2f();
|
||||
result.x = x + vec.x;
|
||||
result.y = y + vec.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>dot</code> calculates the dot product of this vector with a
|
||||
* provided vector. If the provided vector is null, 0 is returned.
|
||||
*
|
||||
* @param vec the vector to dot with this vector.
|
||||
* @return the resultant dot product of this vector and a given vector.
|
||||
*/
|
||||
public float dot(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, 0 returned.");
|
||||
return 0;
|
||||
}
|
||||
return x * vec.x + y * vec.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>cross</code> calculates the cross product of this vector with a
|
||||
* parameter vector v.
|
||||
*
|
||||
* @param v the vector to take the cross product of with this.
|
||||
* @return the cross product vector.
|
||||
*/
|
||||
public Vector3f cross(Vector2f v) {
|
||||
return new Vector3f(0, 0, determinant(v));
|
||||
}
|
||||
|
||||
public float determinant(Vector2f v) {
|
||||
return (x * v.y) - (y * v.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from this to the
|
||||
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
|
||||
*
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a percentage
|
||||
* change from this towards finalVec
|
||||
*/
|
||||
public Vector2f interpolate(Vector2f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from beginVec to
|
||||
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
|
||||
*
|
||||
* @param beginVec The begining vector (delta=0)
|
||||
* @param finalVec The final vector to interpolate towards (delta=1)
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from beginVec towards finalVec
|
||||
*/
|
||||
public Vector2f interpolate(
|
||||
Vector2f beginVec,
|
||||
Vector2f finalVec,
|
||||
float changeAmnt
|
||||
) {
|
||||
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a vector... if it is null or its floats are NaN or infinite, return
|
||||
* false. Else return true.
|
||||
*
|
||||
* @param vector the vector to check
|
||||
* @return true or false as stated above.
|
||||
*/
|
||||
public static boolean isValidVector(Vector2f vector) {
|
||||
if (vector == null)
|
||||
return false;
|
||||
if (
|
||||
Float.isNaN(vector.x)
|
||||
||
|
||||
Float.isNaN(vector.y)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
Float.isInfinite(vector.x)
|
||||
||
|
||||
Float.isInfinite(vector.y)
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>length</code> calculates the magnitude of this vector.
|
||||
*
|
||||
* @return the length or magnitude of the vector.
|
||||
*/
|
||||
public float length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>lengthSquared</code> calculates the squared value of the magnitude
|
||||
* of the vector.
|
||||
*
|
||||
* @return the magnitude squared of the vector.
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance squared.
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(Vector2f v) {
|
||||
double dx = x - v.x;
|
||||
double dy = y - v.y;
|
||||
return (float) (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param otherX The X coordinate of the v vector
|
||||
* @param otherY The Y coordinate of the v vector
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(float otherX, float otherY) {
|
||||
double dx = x - otherX;
|
||||
double dy = y - otherY;
|
||||
return (float) (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distance</code> calculates the distance between this vector and
|
||||
* vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance.
|
||||
* @return the distance between the two vectors.
|
||||
*/
|
||||
public float distance(Vector2f v) {
|
||||
return FastMath.sqrt(distanceSquared(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is returned.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return the new vector.
|
||||
*/
|
||||
public Vector2f mult(float scalar) {
|
||||
return new Vector2f(x * scalar, y * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f multLocal(float scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f multLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x *= vec.x;
|
||||
y *= vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this Vector2f's x and y by the scalar and stores the result in
|
||||
* product. The result is returned for chaining. Similar to
|
||||
* product=this*scalar;
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @param product The vector2f to store the result in.
|
||||
* @return product, after multiplication.
|
||||
*/
|
||||
public Vector2f mult(float scalar, Vector2f product) {
|
||||
if (null == product) {
|
||||
product = new Vector2f();
|
||||
}
|
||||
|
||||
product.x = x * scalar;
|
||||
product.y = y * scalar;
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector2f divide(float scalar) {
|
||||
return new Vector2f(x / scalar, y / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f divideLocal(float scalar) {
|
||||
x /= scalar;
|
||||
y /= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>negate</code> returns the negative of this vector. All values are
|
||||
* negated and set to a new vector.
|
||||
*
|
||||
* @return the negated vector.
|
||||
*/
|
||||
public Vector2f negate() {
|
||||
return new Vector2f(-x, -y);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>negateLocal</code> negates the internal values of this vector.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector2f negateLocal() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector creating a new vector object. If the provided vector is
|
||||
* null, an exception is thrown.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector2f subtract(Vector2f vec) {
|
||||
return subtract(vec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector storing the result in the given vector object. If the
|
||||
* provided vector is null, an exception is thrown.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @param store the vector to store the result in. It is safe for this to be
|
||||
* the same as vec. If null, a new vector is created.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector2f subtract(Vector2f vec, Vector2f store) {
|
||||
if (store == null)
|
||||
store = new Vector2f();
|
||||
store.x = x - vec.x;
|
||||
store.y = y - vec.y;
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtract</code> subtracts the given x,y values from those of this
|
||||
* vector creating a new vector object.
|
||||
*
|
||||
* @param valX value to subtract from x
|
||||
* @param valY value to subtract from y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtract(float valX, float valY) {
|
||||
return new Vector2f(x - valX, y - valY);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtractLocal(Vector2f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts the provided values from this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls.
|
||||
*
|
||||
* @param valX value to subtract from x
|
||||
* @param valY value to subtract from y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f subtractLocal(float valX, float valY) {
|
||||
x -= valX;
|
||||
y -= valY;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalize</code> returns the unit vector of this vector.
|
||||
*
|
||||
* @return unit vector of this vector.
|
||||
*/
|
||||
public Vector2f normalize() {
|
||||
float length = length();
|
||||
if (length != 0) {
|
||||
return divide(length);
|
||||
}
|
||||
|
||||
return divide(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalizeLocal</code> makes this vector into a unit vector of
|
||||
* itself.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector2f normalizeLocal() {
|
||||
float length = length();
|
||||
if (length != 0) {
|
||||
return divideLocal(length);
|
||||
}
|
||||
|
||||
return divideLocal(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>smallestAngleBetween</code> returns (in radians) the minimum angle
|
||||
* between two vectors. It is assumed that both this vector and the given
|
||||
* vector are unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector a unit vector to find the angle against
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float smallestAngleBetween(Vector2f otherVector) {
|
||||
float dotProduct = dot(otherVector);
|
||||
float angle = FastMath.acos(dotProduct);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>angleBetween</code> returns (in radians) the angle required to
|
||||
* rotate a ray represented by this vector to lie colinear to a ray
|
||||
* described by the given vector. It is assumed that both this vector and
|
||||
* the given vector are unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector the "destination" unit vector
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float angleBetween(Vector2f otherVector) {
|
||||
float angle = FastMath.atan2(otherVector.y, otherVector.x)
|
||||
- FastMath.atan2(y, x);
|
||||
return angle;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector2f setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector2f setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>getAngle</code> returns (in radians) the angle represented by this
|
||||
* Vector2f as expressed by a conversion from rectangular coordinates
|
||||
* (<code>x</code>, <code>y</code>) to polar coordinates
|
||||
* (r, <i>theta</i>).
|
||||
*
|
||||
* @return the angle in radians. [-pi, pi)
|
||||
*/
|
||||
public float getAngle() {
|
||||
return FastMath.atan2(y, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>zero</code> resets this vector's data to zero internally.
|
||||
*/
|
||||
public Vector2f zero() {
|
||||
x = y = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>hashCode</code> returns a unique code for this vector object based
|
||||
* on it's values. If two vectors are logically equivalent, they will return
|
||||
* the same hash code value.
|
||||
*
|
||||
* @return the hash code value of this vector.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 37;
|
||||
hash += 37 * hash + Float.floatToIntBits(x);
|
||||
hash += 37 * hash + Float.floatToIntBits(y);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2f clone() {
|
||||
try {
|
||||
return (Vector2f) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(); // can not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this Vector2f into the given float[] object.
|
||||
*
|
||||
* @param floats The float[] to take this Vector2f. If null, a new float[2]
|
||||
* is created.
|
||||
* @return The array, with X, Y float values in that order
|
||||
*/
|
||||
public float[] toArray(float[] floats) {
|
||||
if (floats == null) {
|
||||
floats = new float[2];
|
||||
}
|
||||
floats[0] = x;
|
||||
floats[1] = y;
|
||||
return floats;
|
||||
}
|
||||
|
||||
/**
|
||||
* are these two vectors the same? they are is they both have the same x and
|
||||
* y values.
|
||||
*
|
||||
* @param o the object to compare for equality
|
||||
* @return true if they are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Vector2f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector2f comp = (Vector2f) o;
|
||||
if (Float.compare(x, comp.x) != 0)
|
||||
return false;
|
||||
if (Float.compare(y, comp.y) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>toString</code> returns the string representation of this vector
|
||||
* object. The format of the string is such: com.jme.math.Vector2f
|
||||
* [X=XX.XXXX, Y=YY.YYYY]
|
||||
*
|
||||
* @return the string representation of this vector.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with serialization. Not to be called manually.
|
||||
*
|
||||
* @param in ObjectInput
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
* @see java.io.Externalizable
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException,
|
||||
ClassNotFoundException {
|
||||
x = in.readFloat();
|
||||
y = in.readFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with serialization. Not to be called manually.
|
||||
*
|
||||
* @param out ObjectOutput
|
||||
* @throws IOException
|
||||
* @see java.io.Externalizable
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeFloat(x);
|
||||
out.writeFloat(y);
|
||||
}
|
||||
|
||||
public void rotateAroundOrigin(float angle, boolean cw) {
|
||||
if (cw)
|
||||
angle = -angle;
|
||||
float newX = FastMath.cos(angle) * x - FastMath.sin(angle) * y;
|
||||
float newY = FastMath.sin(angle) * x + FastMath.cos(angle) * y;
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
}
|
||||
1101
src/main/java/com/jme3/math/Vector3f.java
Normal file
1101
src/main/java/com/jme3/math/Vector3f.java
Normal file
File diff suppressed because it is too large
Load Diff
971
src/main/java/com/jme3/math/Vector4f.java
Normal file
971
src/main/java/com/jme3/math/Vector4f.java
Normal file
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.math;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* <code>Vector4f</code> defines a Vector for a four float value tuple.
|
||||
* <code>Vector4f</code> can represent any four dimensional value, such as a
|
||||
* vertex, a normal, etc. Utility methods are also included to aid in
|
||||
* mathematical calculations.
|
||||
*
|
||||
* @author Maarten Steur
|
||||
*/
|
||||
public final class Vector4f implements Cloneable, java.io.Serializable {
|
||||
|
||||
static final long serialVersionUID = 1;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Vector4f.class.getName());
|
||||
|
||||
public final static Vector4f ZERO = new Vector4f(0, 0, 0, 0);
|
||||
public final static Vector4f NAN = new Vector4f(Float.NaN, Float.NaN, Float.NaN, Float.NaN);
|
||||
public final static Vector4f UNIT_X = new Vector4f(1, 0, 0, 0);
|
||||
public final static Vector4f UNIT_Y = new Vector4f(0, 1, 0, 0);
|
||||
public final static Vector4f UNIT_Z = new Vector4f(0, 0, 1, 0);
|
||||
public final static Vector4f UNIT_W = new Vector4f(0, 0, 0, 1);
|
||||
public final static Vector4f UNIT_XYZW = new Vector4f(1, 1, 1, 1);
|
||||
public final static Vector4f POSITIVE_INFINITY = new Vector4f(
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY
|
||||
);
|
||||
public final static Vector4f NEGATIVE_INFINITY = new Vector4f(
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY,
|
||||
Float.NEGATIVE_INFINITY
|
||||
);
|
||||
|
||||
/**
|
||||
* the x value of the vector.
|
||||
*/
|
||||
public float x;
|
||||
|
||||
/**
|
||||
* the y value of the vector.
|
||||
*/
|
||||
public float y;
|
||||
|
||||
/**
|
||||
* the z value of the vector.
|
||||
*/
|
||||
public float z;
|
||||
|
||||
/**
|
||||
* the w value of the vector.
|
||||
*/
|
||||
public float w;
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector3f</code> with default values
|
||||
* of (0,0,0).
|
||||
*
|
||||
*/
|
||||
public Vector4f() {
|
||||
x = y = z = w = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector4f</code> with provides
|
||||
* values.
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @param z the z value of the vector.
|
||||
* @param w the w value of the vector.
|
||||
*/
|
||||
public Vector4f(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor instantiates a new <code>Vector3f</code> that is a copy of
|
||||
* the provided vector
|
||||
*
|
||||
* @param copy The Vector3f to copy
|
||||
*/
|
||||
public Vector4f(Vector4f copy) {
|
||||
this.set(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the x,y,z,w values of the vector based on passed
|
||||
* parameters.
|
||||
*
|
||||
* @param x the x value of the vector.
|
||||
* @param y the y value of the vector.
|
||||
* @param z the z value of the vector.
|
||||
* @param w the w value of the vector.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector4f set(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>set</code> sets the x,y,z values of the vector by copying the
|
||||
* supplied vector.
|
||||
*
|
||||
* @param vect the vector to copy.
|
||||
* @return this vector
|
||||
*/
|
||||
public Vector4f set(Vector4f vect) {
|
||||
this.x = vect.x;
|
||||
this.y = vect.y;
|
||||
this.z = vect.z;
|
||||
this.w = vect.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds a provided vector to this vector creating a
|
||||
* resultant vector which is returned. If the provided vector is null, null
|
||||
* is returned.
|
||||
*
|
||||
* @param vec the vector to add to this.
|
||||
* @return the resultant vector.
|
||||
*/
|
||||
public Vector4f add(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return new Vector4f(x + vec.x, y + vec.y, z + vec.z, w + vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds the values of a provided vector storing the values
|
||||
* in the supplied vector.
|
||||
*
|
||||
* @param vec the vector to add to this
|
||||
* @param result the vector to store the result in
|
||||
* @return result returns the supplied result vector.
|
||||
*/
|
||||
public Vector4f add(Vector4f vec, Vector4f result) {
|
||||
result.x = x + vec.x;
|
||||
result.y = y + vec.y;
|
||||
result.z = z + vec.z;
|
||||
result.w = w + vec.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds a provided vector to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls. If the
|
||||
* provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to add to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f addLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
z += vec.z;
|
||||
w += vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>add</code> adds the provided values to this vector, creating a new
|
||||
* vector that is then returned.
|
||||
*
|
||||
* @param addX the x value to add.
|
||||
* @param addY the y value to add.
|
||||
* @param addZ the z value to add.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f add(float addX, float addY, float addZ, float addW) {
|
||||
return new Vector4f(x + addX, y + addY, z + addZ, w + addW);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLocal</code> adds the provided values to this vector internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param addX value to add to x
|
||||
* @param addY value to add to y
|
||||
* @param addZ value to add to z
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f addLocal(float addX, float addY, float addZ, float addW) {
|
||||
x += addX;
|
||||
y += addY;
|
||||
z += addZ;
|
||||
w += addW;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>scaleAdd</code> multiplies this vector by a scalar then adds the
|
||||
* given Vector3f.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @param add the value to add
|
||||
*/
|
||||
public Vector4f scaleAdd(float scalar, Vector4f add) {
|
||||
x = x * scalar + add.x;
|
||||
y = y * scalar + add.y;
|
||||
z = z * scalar + add.z;
|
||||
w = w * scalar + add.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>scaleAdd</code> multiplies the given vector by a scalar then adds
|
||||
* the given vector.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @param mult the value to multiply the scalar by
|
||||
* @param add the value to add
|
||||
*/
|
||||
public Vector4f scaleAdd(float scalar, Vector4f mult, Vector4f add) {
|
||||
this.x = mult.x * scalar + add.x;
|
||||
this.y = mult.y * scalar + add.y;
|
||||
this.z = mult.z * scalar + add.z;
|
||||
this.w = mult.w * scalar + add.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>dot</code> calculates the dot product of this vector with a
|
||||
* provided vector. If the provided vector is null, 0 is returned.
|
||||
*
|
||||
* @param vec the vector to dot with this vector.
|
||||
* @return the resultant dot product of this vector and a given vector.
|
||||
*/
|
||||
public float dot(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, 0 returned.");
|
||||
return 0;
|
||||
}
|
||||
return x * vec.x + y * vec.y + z * vec.z + w * vec.w;
|
||||
}
|
||||
|
||||
public Vector4f project(Vector4f other) {
|
||||
float n = this.dot(other); // A . B
|
||||
float d = other.lengthSquared(); // |B|^2
|
||||
return new Vector4f(other).normalizeLocal().multLocal(n / d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vector is a unit vector (length() ~= 1), returns
|
||||
* false otherwise.
|
||||
*
|
||||
* @return true if this vector is a unit vector (length() ~= 1), or false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isUnitVector() {
|
||||
float len = length();
|
||||
return 0.99f < len && len < 1.01f;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>length</code> calculates the magnitude of this vector.
|
||||
*
|
||||
* @return the length or magnitude of the vector.
|
||||
*/
|
||||
public float length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>lengthSquared</code> calculates the squared value of the magnitude
|
||||
* of the vector.
|
||||
*
|
||||
* @return the magnitude squared of the vector.
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distanceSquared</code> calculates the distance squared between this
|
||||
* vector and vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance squared.
|
||||
* @return the distance squared between the two vectors.
|
||||
*/
|
||||
public float distanceSquared(Vector4f v) {
|
||||
double dx = x - v.x;
|
||||
double dy = y - v.y;
|
||||
double dz = z - v.z;
|
||||
double dw = w - v.w;
|
||||
return (float) (dx * dx + dy * dy + dz * dz + dw * dw);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>distance</code> calculates the distance between this vector and
|
||||
* vector v.
|
||||
*
|
||||
* @param v the second vector to determine the distance.
|
||||
* @return the distance between the two vectors.
|
||||
*/
|
||||
public float distance(Vector4f v) {
|
||||
return FastMath.sqrt(distanceSquared(v));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is returned.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return the new vector.
|
||||
*/
|
||||
public Vector4f mult(float scalar) {
|
||||
return new Vector4f(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>mult</code> multiplies this vector by a scalar. The resultant
|
||||
* vector is supplied as the second parameter and returned.
|
||||
*
|
||||
* @param scalar the scalar to multiply this vector by.
|
||||
* @param product the product to store the result in.
|
||||
* @return product
|
||||
*/
|
||||
public Vector4f mult(float scalar, Vector4f product) {
|
||||
if (null == product) {
|
||||
product = new Vector4f();
|
||||
}
|
||||
|
||||
product.x = x * scalar;
|
||||
product.y = y * scalar;
|
||||
product.z = z * scalar;
|
||||
product.w = w * scalar;
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param scalar the value to multiply this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(float scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
w *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x *= vec.x;
|
||||
y *= vec.y;
|
||||
z *= vec.z;
|
||||
w *= vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies this vector by 3 scalars internally,
|
||||
* and returns a handle to this vector for easy chaining of calls.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param w
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f multLocal(float x, float y, float z, float w) {
|
||||
this.x *= x;
|
||||
this.y *= y;
|
||||
this.z *= z;
|
||||
this.w *= w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f mult(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
return mult(vec, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>multLocal</code> multiplies a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to mult to this vector.
|
||||
* @param store result vector (null to create a new vector)
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f mult(Vector4f vec, Vector4f store) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
if (store == null)
|
||||
store = new Vector4f();
|
||||
return store.set(x * vec.x, y * vec.y, z * vec.z, w * vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector4f divide(float scalar) {
|
||||
scalar = 1f / scalar;
|
||||
return new Vector4f(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f divideLocal(float scalar) {
|
||||
scalar = 1f / scalar;
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
w *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divide</code> divides the values of this vector by a scalar and
|
||||
* returns the result. The values of this vector remain untouched.
|
||||
*
|
||||
* @param scalar the value to divide this vectors attributes by.
|
||||
* @return the result <code>Vector</code>.
|
||||
*/
|
||||
public Vector4f divide(Vector4f scalar) {
|
||||
return new Vector4f(x / scalar.x, y / scalar.y, z / scalar.z, w / scalar.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>divideLocal</code> divides this vector by a scalar internally, and
|
||||
* returns a handle to this vector for easy chaining of calls. Dividing by
|
||||
* zero will result in an exception.
|
||||
*
|
||||
* @param scalar the value to divides this vector by.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f divideLocal(Vector4f scalar) {
|
||||
x /= scalar.x;
|
||||
y /= scalar.y;
|
||||
z /= scalar.z;
|
||||
w /= scalar.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>negate</code> returns the negative of this vector. All values are
|
||||
* negated and set to a new vector.
|
||||
*
|
||||
* @return the negated vector.
|
||||
*/
|
||||
public Vector4f negate() {
|
||||
return new Vector4f(-x, -y, -z, -w);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>negateLocal</code> negates the internal values of this vector.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector4f negateLocal() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
w = -w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code> subtracts the values of a given vector from those
|
||||
* of this vector creating a new vector object. If the provided vector is
|
||||
* null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract from this vector.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f subtract(Vector4f vec) {
|
||||
return new Vector4f(x - vec.x, y - vec.y, z - vec.z, w - vec.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts a provided vector to this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls. If the provided vector is null, null is returned.
|
||||
*
|
||||
* @param vec the vector to subtract
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f subtractLocal(Vector4f vec) {
|
||||
if (null == vec) {
|
||||
logger.warning("Provided vector is null, null returned.");
|
||||
return null;
|
||||
}
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
z -= vec.z;
|
||||
w -= vec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code>
|
||||
*
|
||||
* @param vec the vector to subtract from this
|
||||
* @param result the vector to store the result in
|
||||
* @return result
|
||||
*/
|
||||
public Vector4f subtract(Vector4f vec, Vector4f result) {
|
||||
if (result == null) {
|
||||
result = new Vector4f();
|
||||
}
|
||||
result.x = x - vec.x;
|
||||
result.y = y - vec.y;
|
||||
result.z = z - vec.z;
|
||||
result.w = w - vec.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <code>subtract</code> subtracts the provided values from this vector,
|
||||
* creating a new vector that is then returned.
|
||||
*
|
||||
* @param subtractX the x value to subtract.
|
||||
* @param subtractY the y value to subtract.
|
||||
* @param subtractZ the z value to subtract.
|
||||
* @param subtractW the w value to subtract.
|
||||
* @return the result vector.
|
||||
*/
|
||||
public Vector4f subtract(float subtractX, float subtractY, float subtractZ, float subtractW) {
|
||||
return new Vector4f(x - subtractX, y - subtractY, z - subtractZ, w - subtractW);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subtractLocal</code> subtracts the provided values from this vector
|
||||
* internally, and returns a handle to this vector for easy chaining of
|
||||
* calls.
|
||||
*
|
||||
* @param subtractX the x value to subtract.
|
||||
* @param subtractY the y value to subtract.
|
||||
* @param subtractZ the z value to subtract.
|
||||
* @param subtractW the w value to subtract.
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f subtractLocal(
|
||||
float subtractX,
|
||||
float subtractY,
|
||||
float subtractZ,
|
||||
float subtractW
|
||||
) {
|
||||
x -= subtractX;
|
||||
y -= subtractY;
|
||||
z -= subtractZ;
|
||||
w -= subtractW;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalize</code> returns the unit vector of this vector.
|
||||
*
|
||||
* @return unit vector of this vector.
|
||||
*/
|
||||
public Vector4f normalize() {
|
||||
// float length = length();
|
||||
// if (length != 0) {
|
||||
// return divide(length);
|
||||
// }
|
||||
//
|
||||
// return divide(1);
|
||||
float length = x * x + y * y + z * z + w * w;
|
||||
if (length != 1f && length != 0f) {
|
||||
length = 1.0f / FastMath.sqrt(length);
|
||||
return new Vector4f(x * length, y * length, z * length, w * length);
|
||||
}
|
||||
return clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>normalizeLocal</code> makes this vector into a unit vector of
|
||||
* itself.
|
||||
*
|
||||
* @return this.
|
||||
*/
|
||||
public Vector4f normalizeLocal() {
|
||||
// NOTE: this implementation is more optimized
|
||||
// than the old jme normalize as this method
|
||||
// is commonly used.
|
||||
float length = x * x + y * y + z * z + w * w;
|
||||
if (length != 1f && length != 0f) {
|
||||
length = 1.0f / FastMath.sqrt(length);
|
||||
x *= length;
|
||||
y *= length;
|
||||
z *= length;
|
||||
w *= length;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>maxLocal</code> computes the maximum value for each component in
|
||||
* this and <code>other</code> vector. The result is stored in this vector.
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
public Vector4f maxLocal(Vector4f other) {
|
||||
x = other.x > x ? other.x : x;
|
||||
y = other.y > y ? other.y : y;
|
||||
z = other.z > z ? other.z : z;
|
||||
w = other.w > w ? other.w : w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>minLocal</code> computes the minimum value for each component in
|
||||
* this and <code>other</code> vector. The result is stored in this vector.
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
public Vector4f minLocal(Vector4f other) {
|
||||
x = other.x < x ? other.x : x;
|
||||
y = other.y < y ? other.y : y;
|
||||
z = other.z < z ? other.z : z;
|
||||
w = other.w < w ? other.w : w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>zero</code> resets this vector's data to zero internally.
|
||||
*/
|
||||
public Vector4f zero() {
|
||||
x = y = z = w = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>angleBetween</code> returns (in radians) the angle between two
|
||||
* vectors. It is assumed that both this vector and the given vector are
|
||||
* unit vectors (iow, normalized).
|
||||
*
|
||||
* @param otherVector a unit vector to find the angle against
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
public float angleBetween(Vector4f otherVector) {
|
||||
float dotProduct = dot(otherVector);
|
||||
float angle = FastMath.acos(dotProduct);
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from this to the
|
||||
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
|
||||
*
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from this towards finalVec
|
||||
*/
|
||||
public Vector4f interpolate(Vector4f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
|
||||
this.z = (1 - changeAmnt) * this.z + changeAmnt * finalVec.z;
|
||||
this.w = (1 - changeAmnt) * this.w + changeAmnt * finalVec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this vector to the interpolation by changeAmnt from beginVec to
|
||||
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
|
||||
*
|
||||
* @param beginVec the beging vector (changeAmnt=0)
|
||||
* @param finalVec The final vector to interpolate towards
|
||||
* @param changeAmnt An amount between 0.0 - 1.0 representing a precentage
|
||||
* change from beginVec towards finalVec
|
||||
*/
|
||||
public Vector4f interpolate(Vector4f beginVec, Vector4f finalVec, float changeAmnt) {
|
||||
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
|
||||
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
|
||||
this.z = (1 - changeAmnt) * beginVec.z + changeAmnt * finalVec.z;
|
||||
this.w = (1 - changeAmnt) * beginVec.w + changeAmnt * finalVec.w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a vector... if it is null or its floats are NaN or infinite, return
|
||||
* false. Else return true.
|
||||
*
|
||||
* @param vector the vector to check
|
||||
* @return true or false as stated above.
|
||||
*/
|
||||
public static boolean isValidVector(Vector4f vector) {
|
||||
if (vector == null)
|
||||
return false;
|
||||
if (
|
||||
Float.isNaN(vector.x)
|
||||
||
|
||||
Float.isNaN(vector.y)
|
||||
||
|
||||
Float.isNaN(vector.z)
|
||||
||
|
||||
Float.isNaN(vector.w)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
Float.isInfinite(vector.x)
|
||||
||
|
||||
Float.isInfinite(vector.y)
|
||||
||
|
||||
Float.isInfinite(vector.z)
|
||||
||
|
||||
Float.isInfinite(vector.w)
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector4f clone() {
|
||||
try {
|
||||
return (Vector4f) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(); // can not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this Vector3f into the given float[] object.
|
||||
*
|
||||
* @param floats The float[] to take this Vector3f. If null, a new float[3]
|
||||
* is created.
|
||||
* @return The array, with X, Y, Z float values in that order
|
||||
*/
|
||||
public float[] toArray(float[] floats) {
|
||||
if (floats == null) {
|
||||
floats = new float[4];
|
||||
}
|
||||
floats[0] = x;
|
||||
floats[1] = y;
|
||||
floats[2] = z;
|
||||
floats[3] = w;
|
||||
return floats;
|
||||
}
|
||||
|
||||
/**
|
||||
* are these two vectors the same? they are is they both have the same x,y,
|
||||
* and z values.
|
||||
*
|
||||
* @param o the object to compare for equality
|
||||
* @return true if they are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Vector4f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector4f comp = (Vector4f) o;
|
||||
if (Float.compare(x, comp.x) != 0)
|
||||
return false;
|
||||
if (Float.compare(y, comp.y) != 0)
|
||||
return false;
|
||||
if (Float.compare(z, comp.z) != 0)
|
||||
return false;
|
||||
if (Float.compare(w, comp.w) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>hashCode</code> returns a unique code for this vector object based
|
||||
* on it's values. If two vectors are logically equivalent, they will return
|
||||
* the same hash code value.
|
||||
*
|
||||
* @return the hash code value of this vector.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 37;
|
||||
hash += 37 * hash + Float.floatToIntBits(x);
|
||||
hash += 37 * hash + Float.floatToIntBits(y);
|
||||
hash += 37 * hash + Float.floatToIntBits(z);
|
||||
hash += 37 * hash + Float.floatToIntBits(w);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>toString</code> returns the string representation of this vector.
|
||||
* The format is:
|
||||
*
|
||||
* org.jme.math.Vector3f [X=XX.XXXX, Y=YY.YYYY, Z=ZZ.ZZZZ, W=WW.WWWW]
|
||||
*
|
||||
* @return the string representation of this vector.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ", " + z + ", " + w + ")";
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector4f setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector4f setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector4f setZ(float z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
public Vector4f setW(float w) {
|
||||
this.w = w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return x value if index == 0, y value if index == 1 or z value if index
|
||||
* == 2
|
||||
* @throws IllegalArgumentException if index is not one of 0, 1, 2.
|
||||
*/
|
||||
public float get(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return x;
|
||||
case 1:
|
||||
return y;
|
||||
case 2:
|
||||
return z;
|
||||
case 3:
|
||||
return w;
|
||||
}
|
||||
throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index which field index in this vector to set.
|
||||
* @param value to set to one of x, y, z or w.
|
||||
* @throws IllegalArgumentException if index is not one of 0, 1, 2, 3.
|
||||
*/
|
||||
public void set(int index, float value) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
x = value;
|
||||
return;
|
||||
case 1:
|
||||
y = value;
|
||||
return;
|
||||
case 2:
|
||||
z = value;
|
||||
return;
|
||||
case 3:
|
||||
w = value;
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("index must be either 0, 1, 2 or 3");
|
||||
}
|
||||
|
||||
}
|
||||
105
src/main/java/com/jme3/system/NanoTimer.java
Normal file
105
src/main/java/com/jme3/system/NanoTimer.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.system;
|
||||
|
||||
/**
|
||||
* <code>NanoTimer</code> is a System.nanoTime implementation of
|
||||
* <code>Timer</code>. This is primarily useful for headless applications
|
||||
* running on a server.
|
||||
*
|
||||
* @author Matthew D. Hicks
|
||||
*/
|
||||
public class NanoTimer extends Timer {
|
||||
|
||||
private static final long TIMER_RESOLUTION = 1000000000L;
|
||||
private static final float INVERSE_TIMER_RESOLUTION = 1f / TIMER_RESOLUTION;
|
||||
|
||||
private long startTime;
|
||||
private long previousTime;
|
||||
private float tpf;
|
||||
private float fps;
|
||||
private long currentTime;
|
||||
|
||||
public NanoTimer() {
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in seconds. The timer starts at 0.0 seconds.
|
||||
*
|
||||
* @return the current time in seconds
|
||||
*/
|
||||
|
||||
protected long getTimeInternal() {
|
||||
return System.nanoTime() - startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTimeInSeconds() {
|
||||
return getTime() * INVERSE_TIMER_RESOLUTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getResolution() {
|
||||
return TIMER_RESOLUTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFrameRate() {
|
||||
return fps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTimePerFrame() {
|
||||
return tpf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
currentTime = getTimeInternal();
|
||||
tpf = (currentTime - previousTime) * (1.0f / TIMER_RESOLUTION);
|
||||
fps = 1.0f / tpf;
|
||||
previousTime = getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
startTime = System.nanoTime();
|
||||
currentTime = getTimeInternal();
|
||||
previousTime = getTime();
|
||||
}
|
||||
}
|
||||
93
src/main/java/com/jme3/system/Timer.java
Normal file
93
src/main/java/com/jme3/system/Timer.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.system;
|
||||
|
||||
/**
|
||||
* <code>Timer</code> is the base class for a high resolution timer. It is
|
||||
* created from getTimer("display system")
|
||||
*
|
||||
* @author Mark Powell
|
||||
* @version $Id: Timer.java,v 1.18 2007/03/09 10:19:34 rherlitz Exp $
|
||||
*/
|
||||
public abstract class Timer {
|
||||
|
||||
/**
|
||||
* Returns the current time in ticks. A tick is an arbitrary measure of time
|
||||
* defined by the timer implementation. The number of ticks per second is
|
||||
* given by <code>getResolution()</code>. The timer starts at 0 ticks.
|
||||
*
|
||||
* @return a long value representing the current time
|
||||
*/
|
||||
public abstract long getTime();
|
||||
|
||||
/**
|
||||
* Returns the time in seconds. The timer starts at 0.0 seconds.
|
||||
*
|
||||
* @return the current time in seconds
|
||||
*/
|
||||
public float getTimeInSeconds() {
|
||||
return getTime() / (float) getResolution();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolution of the timer.
|
||||
*
|
||||
* @return the number of timer ticks per second
|
||||
*/
|
||||
public abstract long getResolution();
|
||||
|
||||
/**
|
||||
* Returns the "calls per second". If this is called every frame, then it
|
||||
* will return the "frames per second".
|
||||
*
|
||||
* @return The "calls per second".
|
||||
*/
|
||||
public abstract float getFrameRate();
|
||||
|
||||
/**
|
||||
* Returns the time, in seconds, between the last call and the current one.
|
||||
*
|
||||
* @return Time between this call and the last one.
|
||||
*/
|
||||
public abstract float getTimePerFrame();
|
||||
|
||||
/**
|
||||
* <code>update</code> recalculates the frame rate based on the previous
|
||||
* call to update. It is assumed that update is called each frame.
|
||||
*/
|
||||
public abstract void update();
|
||||
|
||||
/**
|
||||
* Reset the timer to 0. Clear any tpf history.
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
||||
117
src/main/java/dev/slimevr/Main.java
Normal file
117
src/main/java/dev/slimevr/Main.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package dev.slimevr;
|
||||
|
||||
import dev.slimevr.gui.Keybinding;
|
||||
import dev.slimevr.gui.VRServerGUI;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.lang3.JavaVersion;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
|
||||
public class Main {
|
||||
|
||||
public static String VERSION = "0.2.1";
|
||||
|
||||
public static VRServer vrServer;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
CommandLine cmd = null;
|
||||
|
||||
Options options = new Options();
|
||||
|
||||
Option noGui = new Option(
|
||||
"g",
|
||||
"no-gui",
|
||||
false,
|
||||
"disable swing gui (allow for other gui to be used)"
|
||||
);
|
||||
Option help = new Option("h", "help", false, "Show help");
|
||||
|
||||
options.addOption(noGui);
|
||||
options.addOption(help);
|
||||
try {
|
||||
cmd = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
System.out.println(e.getMessage());
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (cmd.hasOption("help")) {
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
File dir = new File("").getAbsoluteFile();
|
||||
try {
|
||||
LogManager.initialize(new File(dir, "logs/"), dir);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
if (!SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_17)) {
|
||||
LogManager.severe("SlimeVR start-up error! A minimum of Java 17 is required.");
|
||||
JOptionPane
|
||||
.showMessageDialog(
|
||||
null,
|
||||
"SlimeVR start-up error! A minimum of Java 17 is required.",
|
||||
"SlimeVR: Java Runtime Mismatch",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
new ServerSocket(6969).close();
|
||||
new ServerSocket(35903).close();
|
||||
new ServerSocket(21110).close();
|
||||
} catch (IOException e) {
|
||||
LogManager
|
||||
.severe(
|
||||
"SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running."
|
||||
);
|
||||
JOptionPane
|
||||
.showMessageDialog(
|
||||
null,
|
||||
"SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.",
|
||||
"SlimeVR: Ports are busy",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
vrServer = new VRServer();
|
||||
vrServer.start();
|
||||
new Keybinding(vrServer);
|
||||
if (!cmd.hasOption("no-gui"))
|
||||
new VRServerGUI(vrServer);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e2) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(1); // Exit in case error happened on init and window
|
||||
// not appeared, but some thread
|
||||
// started
|
||||
} finally {
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/main/java/dev/slimevr/NetworkProtocol.java
Normal file
8
src/main/java/dev/slimevr/NetworkProtocol.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package dev.slimevr;
|
||||
|
||||
public enum NetworkProtocol {
|
||||
OWO_LEGACY,
|
||||
SLIMEVR_RAW,
|
||||
SLIMEVR_FLATBUFFER,
|
||||
SLIMEVR_WEBSOCKET
|
||||
}
|
||||
321
src/main/java/dev/slimevr/VRServer.java
Normal file
321
src/main/java/dev/slimevr/VRServer.java
Normal file
@@ -0,0 +1,321 @@
|
||||
package dev.slimevr;
|
||||
|
||||
import com.jme3.system.NanoTimer;
|
||||
import dev.slimevr.autobone.AutoBoneHandler;
|
||||
import dev.slimevr.bridge.Bridge;
|
||||
import dev.slimevr.bridge.VMCBridge;
|
||||
import dev.slimevr.config.ConfigManager;
|
||||
import dev.slimevr.platform.windows.WindowsNamedPipeBridge;
|
||||
import dev.slimevr.poserecorder.BVHRecorder;
|
||||
import dev.slimevr.protocol.ProtocolAPI;
|
||||
import dev.slimevr.serial.SerialHandler;
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.DeviceManager;
|
||||
import dev.slimevr.vr.processor.HumanPoseProcessor;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import dev.slimevr.vr.trackers.HMDTracker;
|
||||
import dev.slimevr.vr.trackers.ShareableTracker;
|
||||
import dev.slimevr.vr.trackers.Tracker;
|
||||
import dev.slimevr.vr.trackers.udp.TrackersUDPServer;
|
||||
import dev.slimevr.websocketapi.WebSocketVRBridge;
|
||||
import io.eiren.util.OperatingSystem;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.ann.ThreadSecure;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import solarxr_protocol.datatypes.TrackerIdT;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
public class VRServer extends Thread {
|
||||
|
||||
public final HumanPoseProcessor humanPoseProcessor;
|
||||
public final HMDTracker hmdTracker;
|
||||
private final List<Tracker> trackers = new FastList<>();
|
||||
private final TrackersUDPServer trackersServer;
|
||||
private final List<Bridge> bridges = new FastList<>();
|
||||
private final Queue<Runnable> tasks = new LinkedBlockingQueue<>();
|
||||
private final List<Consumer<Tracker>> newTrackersConsumers = new FastList<>();
|
||||
private final List<Runnable> onTick = new FastList<>();
|
||||
private final List<? extends ShareableTracker> shareTrackers;
|
||||
private final DeviceManager deviceManager;
|
||||
private final BVHRecorder bvhRecorder;
|
||||
private final SerialHandler serialHandler;
|
||||
private final AutoBoneHandler autoBoneHandler;
|
||||
private final ProtocolAPI protocolAPI;
|
||||
private final ConfigManager configManager;
|
||||
private final NanoTimer fpsTimer = new NanoTimer();
|
||||
|
||||
/**
|
||||
* This function is used by VRWorkout, do not remove!
|
||||
*/
|
||||
public VRServer() {
|
||||
this("vrconfig.yml");
|
||||
}
|
||||
|
||||
public VRServer(String configPath) {
|
||||
super("VRServer");
|
||||
|
||||
this.configManager = new ConfigManager(configPath);
|
||||
this.configManager.loadConfig();
|
||||
|
||||
deviceManager = new DeviceManager(this);
|
||||
|
||||
serialHandler = new SerialHandler();
|
||||
autoBoneHandler = new AutoBoneHandler(this);
|
||||
protocolAPI = new ProtocolAPI(this);
|
||||
|
||||
hmdTracker = new HMDTracker("HMD");
|
||||
hmdTracker.position.set(0, 1.8f, 0); // Set starting position for easier
|
||||
// debugging
|
||||
// TODO Multiple processors
|
||||
humanPoseProcessor = new HumanPoseProcessor(this, hmdTracker);
|
||||
shareTrackers = humanPoseProcessor.getComputedTrackers();
|
||||
|
||||
// Start server for SlimeVR trackers
|
||||
trackersServer = new TrackersUDPServer(6969, "Sensors UDP server", this::registerTracker);
|
||||
|
||||
// OpenVR bridge currently only supports Windows
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) {
|
||||
|
||||
// Create named pipe bridge for SteamVR driver
|
||||
WindowsNamedPipeBridge driverBridge = new WindowsNamedPipeBridge(
|
||||
this,
|
||||
hmdTracker,
|
||||
"steamvr",
|
||||
"SteamVR Driver Bridge",
|
||||
"\\\\.\\pipe\\SlimeVRDriver",
|
||||
shareTrackers
|
||||
);
|
||||
tasks.add(driverBridge::startBridge);
|
||||
bridges.add(driverBridge);
|
||||
|
||||
// Create named pipe bridge for SteamVR input
|
||||
// TODO: how do we want to handle HMD input from the feeder app?
|
||||
WindowsNamedPipeBridge feederBridge = new WindowsNamedPipeBridge(
|
||||
this,
|
||||
null,
|
||||
"steamvr_feeder",
|
||||
"SteamVR Feeder Bridge",
|
||||
"\\\\.\\pipe\\SlimeVRInput",
|
||||
new FastList<>()
|
||||
);
|
||||
tasks.add(feederBridge::startBridge);
|
||||
bridges.add(feederBridge);
|
||||
}
|
||||
|
||||
// Create WebSocket server
|
||||
WebSocketVRBridge wsBridge = new WebSocketVRBridge(hmdTracker, shareTrackers, this);
|
||||
tasks.add(wsBridge::startBridge);
|
||||
bridges.add(wsBridge);
|
||||
|
||||
// Create VMCBridge
|
||||
try {
|
||||
VMCBridge vmcBridge = new VMCBridge(39539, 39540, InetAddress.getLocalHost());
|
||||
tasks.add(vmcBridge::startBridge);
|
||||
bridges.add(vmcBridge);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
bvhRecorder = new BVHRecorder(this);
|
||||
|
||||
registerTracker(hmdTracker);
|
||||
for (Tracker tracker : shareTrackers) {
|
||||
registerTracker(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasBridge(Class<? extends Bridge> bridgeClass) {
|
||||
for (Bridge bridge : bridges) {
|
||||
if (bridgeClass.isAssignableFrom(bridge.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public <E extends Bridge> E getVRBridge(Class<E> bridgeClass) {
|
||||
for (Bridge bridge : bridges) {
|
||||
if (bridgeClass.isAssignableFrom(bridge.getClass())) {
|
||||
return bridgeClass.cast(bridge);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void addOnTick(Runnable runnable) {
|
||||
this.onTick.add(runnable);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void addNewTrackerConsumer(Consumer<Tracker> consumer) {
|
||||
queueTask(() -> {
|
||||
newTrackersConsumers.add(consumer);
|
||||
for (Tracker tracker : trackers) {
|
||||
consumer.accept(tracker);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void trackerUpdated(Tracker tracker) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.trackerUpdated(tracker);
|
||||
this.getConfigManager().getVrConfig().writeTrackerConfig(tracker);
|
||||
this.getConfigManager().saveConfig();
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void addSkeletonUpdatedCallback(Consumer<Skeleton> consumer) {
|
||||
queueTask(() -> humanPoseProcessor.addSkeletonUpdatedCallback(consumer));
|
||||
}
|
||||
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void run() {
|
||||
trackersServer.start();
|
||||
while (true) {
|
||||
fpsTimer.update();
|
||||
// final long start = System.currentTimeMillis();
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task == null)
|
||||
break;
|
||||
task.run();
|
||||
} while (true);
|
||||
for (Runnable task : onTick) {
|
||||
task.run();
|
||||
}
|
||||
for (Bridge bridge : bridges) {
|
||||
bridge.dataRead();
|
||||
}
|
||||
for (Tracker tracker : trackers) {
|
||||
tracker.tick();
|
||||
}
|
||||
humanPoseProcessor.update();
|
||||
for (Bridge bridge : bridges) {
|
||||
bridge.dataWrite();
|
||||
}
|
||||
// final long time = System.currentTimeMillis() - start;
|
||||
try {
|
||||
Thread.sleep(1); // 1000Hz
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void queueTask(Runnable r) {
|
||||
tasks.add(r);
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
private void trackerAdded(Tracker tracker) {
|
||||
humanPoseProcessor.trackerAdded(tracker);
|
||||
}
|
||||
|
||||
@ThreadSecure
|
||||
public void registerTracker(Tracker tracker) {
|
||||
this.getConfigManager().getVrConfig().readTrackerConfig(tracker);
|
||||
queueTask(() -> {
|
||||
trackers.add(tracker);
|
||||
trackerAdded(tracker);
|
||||
for (Consumer<Tracker> tc : newTrackersConsumers) {
|
||||
tc.accept(tracker);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void resetTrackers() {
|
||||
queueTask(humanPoseProcessor::resetTrackers);
|
||||
}
|
||||
|
||||
public void resetTrackersYaw() {
|
||||
queueTask(humanPoseProcessor::resetTrackersYaw);
|
||||
}
|
||||
|
||||
public void setLegTweaksEnabled(boolean value) {
|
||||
queueTask(() -> humanPoseProcessor.setLegTweaksEnabled(value));
|
||||
}
|
||||
|
||||
public void setSkatingReductionEnabled(boolean value) {
|
||||
queueTask(() -> humanPoseProcessor.setSkatingCorrectionEnabled(value));
|
||||
}
|
||||
|
||||
public void setFloorClipEnabled(boolean value) {
|
||||
queueTask(() -> humanPoseProcessor.setFloorClipEnabled(value));
|
||||
}
|
||||
|
||||
public int getTrackersCount() {
|
||||
return trackers.size();
|
||||
}
|
||||
|
||||
public List<Tracker> getAllTrackers() {
|
||||
return new FastList<>(trackers);
|
||||
}
|
||||
|
||||
public Tracker getTrackerById(TrackerIdT id) {
|
||||
for (Tracker tracker : trackers) {
|
||||
if (tracker.getTrackerNum() != id.getTrackerNum()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle synthetic devices
|
||||
if (id.getDeviceId() == null && tracker.getDevice() == null) {
|
||||
return tracker;
|
||||
}
|
||||
|
||||
if (
|
||||
tracker.getDevice() != null
|
||||
&& id.getDeviceId() != null
|
||||
&& id.getDeviceId().getId() == tracker.getDevice().getId()
|
||||
) {
|
||||
// This is a physical tracker, and both device id and the
|
||||
// tracker num match
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BVHRecorder getBvhRecorder() {
|
||||
return this.bvhRecorder;
|
||||
}
|
||||
|
||||
public SerialHandler getSerialHandler() {
|
||||
return this.serialHandler;
|
||||
}
|
||||
|
||||
public AutoBoneHandler getAutoBoneHandler() {
|
||||
return this.autoBoneHandler;
|
||||
}
|
||||
|
||||
public ProtocolAPI getProtocolAPI() {
|
||||
return protocolAPI;
|
||||
}
|
||||
|
||||
public TrackersUDPServer getTrackersServer() {
|
||||
return trackersServer;
|
||||
}
|
||||
|
||||
public DeviceManager getDeviceManager() {
|
||||
return deviceManager;
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public NanoTimer getFpsTimer() {
|
||||
return fpsTimer;
|
||||
}
|
||||
|
||||
}
|
||||
908
src/main/java/dev/slimevr/autobone/AutoBone.java
Normal file
908
src/main/java/dev/slimevr/autobone/AutoBone.java
Normal file
@@ -0,0 +1,908 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector3f;
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.autobone.errors.*;
|
||||
import dev.slimevr.config.AutoBoneConfig;
|
||||
import dev.slimevr.poserecorder.PoseFrameIO;
|
||||
import dev.slimevr.poserecorder.PoseFrameSkeleton;
|
||||
import dev.slimevr.poserecorder.PoseFrameTracker;
|
||||
import dev.slimevr.poserecorder.PoseFrames;
|
||||
import dev.slimevr.vr.processor.HumanPoseProcessor;
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
import dev.slimevr.vr.processor.skeleton.*;
|
||||
import dev.slimevr.vr.trackers.TrackerRole;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
public class AutoBone {
|
||||
|
||||
private static final File saveDir = new File("AutoBone Recordings");
|
||||
private static final File loadDir = new File("Load AutoBone Recordings");
|
||||
|
||||
// This is filled by reloadConfigValues()
|
||||
public final EnumMap<BoneType, Float> offsets = new EnumMap<>(
|
||||
BoneType.class
|
||||
);
|
||||
|
||||
public final FastList<BoneType> adjustOffsets = new FastList<>(
|
||||
new BoneType[] {
|
||||
BoneType.HEAD,
|
||||
BoneType.NECK,
|
||||
BoneType.CHEST,
|
||||
BoneType.WAIST,
|
||||
BoneType.HIP,
|
||||
|
||||
// This now works when using body proportion error! It's not the
|
||||
// best still but it is somewhat functional
|
||||
BoneType.LEFT_HIP,
|
||||
|
||||
BoneType.LEFT_UPPER_LEG,
|
||||
BoneType.LEFT_LOWER_LEG,
|
||||
}
|
||||
);
|
||||
|
||||
public final FastList<BoneType> heightOffsets = new FastList<>(
|
||||
new BoneType[] {
|
||||
BoneType.NECK,
|
||||
BoneType.CHEST,
|
||||
BoneType.WAIST,
|
||||
BoneType.HIP,
|
||||
|
||||
BoneType.LEFT_UPPER_LEG,
|
||||
BoneType.RIGHT_UPPER_LEG,
|
||||
BoneType.LEFT_LOWER_LEG,
|
||||
BoneType.RIGHT_LOWER_LEG,
|
||||
}
|
||||
);
|
||||
|
||||
public final FastList<SkeletonConfigOffsets> legacyHeightConfigs = new FastList<>(
|
||||
new SkeletonConfigOffsets[] {
|
||||
SkeletonConfigOffsets.NECK,
|
||||
SkeletonConfigOffsets.TORSO,
|
||||
|
||||
SkeletonConfigOffsets.LEGS_LENGTH,
|
||||
}
|
||||
);
|
||||
|
||||
public final EnumMap<SkeletonConfigOffsets, Float> legacyConfigs = new EnumMap<>(
|
||||
SkeletonConfigOffsets.class
|
||||
);
|
||||
|
||||
protected final VRServer server;
|
||||
|
||||
// #region Error functions
|
||||
public SlideError slideError = new SlideError();
|
||||
public OffsetSlideError offsetSlideError = new OffsetSlideError();
|
||||
public FootHeightOffsetError footHeightOffsetError = new FootHeightOffsetError();
|
||||
public BodyProportionError bodyProportionError = new BodyProportionError();
|
||||
public HeightError heightError = new HeightError();
|
||||
public PositionError positionError = new PositionError();
|
||||
public PositionOffsetError positionOffsetError = new PositionOffsetError();
|
||||
// #endregion
|
||||
|
||||
private final Random rand = new Random();
|
||||
|
||||
private final AutoBoneConfig config;
|
||||
|
||||
public AutoBone(VRServer server) {
|
||||
this.config = server.getConfigManager().getVrConfig().getAutoBone();
|
||||
this.server = server;
|
||||
reloadConfigValues();
|
||||
}
|
||||
|
||||
// Mean square error function
|
||||
protected static float errorFunc(float errorDeriv) {
|
||||
return 0.5f * (errorDeriv * errorDeriv);
|
||||
}
|
||||
|
||||
public static File getLoadDir() {
|
||||
return loadDir;
|
||||
}
|
||||
|
||||
public float computeBoneOffset(BoneType bone, SkeletonConfig skeletonConfig) {
|
||||
return switch (bone) {
|
||||
case HEAD -> skeletonConfig.getOffset(SkeletonConfigOffsets.HEAD);
|
||||
case NECK -> skeletonConfig.getOffset(SkeletonConfigOffsets.NECK);
|
||||
case CHEST -> skeletonConfig.getOffset(SkeletonConfigOffsets.CHEST);
|
||||
case WAIST -> -skeletonConfig.getOffset(SkeletonConfigOffsets.CHEST)
|
||||
+ skeletonConfig.getOffset(SkeletonConfigOffsets.TORSO)
|
||||
- skeletonConfig.getOffset(SkeletonConfigOffsets.WAIST);
|
||||
case HIP -> skeletonConfig.getOffset(SkeletonConfigOffsets.WAIST);
|
||||
case LEFT_HIP, RIGHT_HIP -> skeletonConfig.getOffset(SkeletonConfigOffsets.HIPS_WIDTH)
|
||||
/ 2f;
|
||||
case LEFT_UPPER_LEG, RIGHT_UPPER_LEG -> skeletonConfig
|
||||
.getOffset(SkeletonConfigOffsets.LEGS_LENGTH)
|
||||
- skeletonConfig.getOffset(SkeletonConfigOffsets.KNEE_HEIGHT);
|
||||
case LEFT_LOWER_LEG, RIGHT_LOWER_LEG -> skeletonConfig
|
||||
.getOffset(SkeletonConfigOffsets.KNEE_HEIGHT);
|
||||
default -> -1f;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public void reloadConfigValues() {
|
||||
reloadConfigValues(null);
|
||||
}
|
||||
|
||||
public void reloadConfigValues(List<PoseFrameTracker> trackers) {
|
||||
// Remove all previous values
|
||||
offsets.clear();
|
||||
|
||||
// Get current or default skeleton configs
|
||||
Skeleton skeleton = getSkeleton();
|
||||
SkeletonConfig skeletonConfig = skeleton != null
|
||||
? skeleton.getSkeletonConfig()
|
||||
: new SkeletonConfig(false);
|
||||
|
||||
for (BoneType bone : adjustOffsets) {
|
||||
float offset = computeBoneOffset(bone, skeletonConfig);
|
||||
if (offset > 0f) {
|
||||
offsets.put(bone, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3f getBoneDirection(
|
||||
HumanSkeleton skeleton,
|
||||
BoneType node,
|
||||
boolean rightSide,
|
||||
Vector3f buffer
|
||||
) {
|
||||
if (buffer == null) {
|
||||
buffer = new Vector3f();
|
||||
}
|
||||
|
||||
switch (node) {
|
||||
case LEFT_HIP, RIGHT_HIP -> node = rightSide ? BoneType.RIGHT_HIP : BoneType.LEFT_HIP;
|
||||
case LEFT_UPPER_LEG, RIGHT_UPPER_LEG -> node = rightSide
|
||||
? BoneType.RIGHT_UPPER_LEG
|
||||
: BoneType.LEFT_UPPER_LEG;
|
||||
case LEFT_LOWER_LEG, RIGHT_LOWER_LEG -> node = rightSide
|
||||
? BoneType.RIGHT_LOWER_LEG
|
||||
: BoneType.LEFT_LOWER_LEG;
|
||||
}
|
||||
|
||||
TransformNode relevantTransform = skeleton.getTailNodeOfBone(node);
|
||||
return relevantTransform.worldTransform
|
||||
.getTranslation()
|
||||
.subtract(relevantTransform.getParent().worldTransform.getTranslation(), buffer)
|
||||
.normalizeLocal();
|
||||
}
|
||||
|
||||
public float getDotProductDiff(
|
||||
HumanSkeleton skeleton1,
|
||||
HumanSkeleton skeleton2,
|
||||
BoneType node,
|
||||
boolean rightSide,
|
||||
Vector3f offset
|
||||
) {
|
||||
Vector3f normalizedOffset = offset.normalize();
|
||||
|
||||
Vector3f boneRotation = new Vector3f();
|
||||
getBoneDirection(skeleton1, node, rightSide, boneRotation);
|
||||
float dot1 = normalizedOffset.dot(boneRotation);
|
||||
|
||||
getBoneDirection(skeleton2, node, rightSide, boneRotation);
|
||||
float dot2 = normalizedOffset.dot(boneRotation);
|
||||
|
||||
return dot2 - dot1;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple utility method to get the {@link Skeleton} from the
|
||||
* {@link VRServer}
|
||||
*
|
||||
* @return The {@link Skeleton} associated with the {@link VRServer}, or
|
||||
* null if there is none available
|
||||
* @see {@link VRServer}, {@link Skeleton}
|
||||
*/
|
||||
private Skeleton getSkeleton() {
|
||||
HumanPoseProcessor humanPoseProcessor = server != null ? server.humanPoseProcessor : null;
|
||||
return humanPoseProcessor != null ? humanPoseProcessor.getSkeleton() : null;
|
||||
}
|
||||
|
||||
public void applyAndSaveConfig() {
|
||||
if (!applyAndSaveConfig(getSkeleton())) {
|
||||
// Unable to apply to skeleton, save directly
|
||||
// saveConfigs();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applyConfig(
|
||||
BiConsumer<SkeletonConfigOffsets, Float> configConsumer,
|
||||
Map<BoneType, Float> offsets
|
||||
) {
|
||||
if (configConsumer == null || offsets == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Float headOffset = offsets.get(BoneType.HEAD);
|
||||
if (headOffset != null) {
|
||||
configConsumer.accept(SkeletonConfigOffsets.HEAD, headOffset);
|
||||
}
|
||||
|
||||
Float neckOffset = offsets.get(BoneType.NECK);
|
||||
if (neckOffset != null) {
|
||||
configConsumer.accept(SkeletonConfigOffsets.NECK, neckOffset);
|
||||
}
|
||||
|
||||
Float chestOffset = offsets.get(BoneType.CHEST);
|
||||
Float hipOffset = offsets.get(BoneType.HIP);
|
||||
Float waistOffset = offsets.get(BoneType.WAIST);
|
||||
if (chestOffset != null && hipOffset != null && waistOffset != null) {
|
||||
configConsumer
|
||||
.accept(SkeletonConfigOffsets.TORSO, chestOffset + hipOffset + waistOffset);
|
||||
}
|
||||
|
||||
if (chestOffset != null) {
|
||||
configConsumer.accept(SkeletonConfigOffsets.CHEST, chestOffset);
|
||||
}
|
||||
|
||||
if (hipOffset != null) {
|
||||
configConsumer.accept(SkeletonConfigOffsets.WAIST, hipOffset);
|
||||
}
|
||||
|
||||
Float hipWidthOffset = offsets.get(BoneType.LEFT_HIP);
|
||||
if (hipWidthOffset == null) {
|
||||
hipWidthOffset = offsets.get(BoneType.RIGHT_HIP);
|
||||
}
|
||||
if (hipWidthOffset != null) {
|
||||
configConsumer
|
||||
.accept(SkeletonConfigOffsets.HIPS_WIDTH, hipWidthOffset * 2f);
|
||||
}
|
||||
|
||||
Float upperLegOffset = offsets.get(BoneType.LEFT_UPPER_LEG);
|
||||
if (upperLegOffset == null) {
|
||||
upperLegOffset = offsets.get(BoneType.RIGHT_UPPER_LEG);
|
||||
}
|
||||
Float lowerLegOffset = offsets.get(BoneType.LEFT_LOWER_LEG);
|
||||
if (lowerLegOffset == null) {
|
||||
lowerLegOffset = offsets.get(BoneType.RIGHT_LOWER_LEG);
|
||||
}
|
||||
if (upperLegOffset != null && lowerLegOffset != null) {
|
||||
configConsumer
|
||||
.accept(SkeletonConfigOffsets.LEGS_LENGTH, upperLegOffset + lowerLegOffset);
|
||||
}
|
||||
|
||||
if (lowerLegOffset != null) {
|
||||
configConsumer.accept(SkeletonConfigOffsets.KNEE_HEIGHT, lowerLegOffset);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applyConfig(BiConsumer<SkeletonConfigOffsets, Float> configConsumer) {
|
||||
return applyConfig(configConsumer, offsets);
|
||||
}
|
||||
|
||||
public boolean applyConfig(
|
||||
Map<SkeletonConfigOffsets, Float> skeletonConfig,
|
||||
Map<BoneType, Float> offsets
|
||||
) {
|
||||
if (skeletonConfig == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return applyConfig(skeletonConfig::put, offsets);
|
||||
}
|
||||
|
||||
public boolean applyConfig(Map<SkeletonConfigOffsets, Float> skeletonConfig) {
|
||||
return applyConfig(skeletonConfig, offsets);
|
||||
}
|
||||
|
||||
public boolean applyConfig(SkeletonConfig skeletonConfig, Map<BoneType, Float> offsets) {
|
||||
if (skeletonConfig == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return applyConfig(skeletonConfig::setOffset, offsets);
|
||||
}
|
||||
|
||||
public boolean applyConfig(SkeletonConfig skeletonConfig) {
|
||||
return applyConfig(skeletonConfig, offsets);
|
||||
}
|
||||
|
||||
public boolean applyAndSaveConfig(Skeleton skeleton) {
|
||||
if (skeleton == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkeletonConfig skeletonConfig = skeleton.getSkeletonConfig();
|
||||
if (!applyConfig(skeletonConfig))
|
||||
return false;
|
||||
|
||||
skeletonConfig.save();
|
||||
server.getConfigManager().saveConfig();
|
||||
|
||||
LogManager.info("[AutoBone] Configured skeleton bone lengths");
|
||||
return true;
|
||||
}
|
||||
|
||||
public Float getConfig(BoneType config) {
|
||||
return offsets.get(config);
|
||||
}
|
||||
|
||||
public <T> float sumSelectConfigs(
|
||||
List<T> selection,
|
||||
Function<T, Float> configs
|
||||
) {
|
||||
float sum = 0f;
|
||||
|
||||
for (T config : selection) {
|
||||
Float length = configs.apply(config);
|
||||
if (length != null) {
|
||||
sum += length;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public <T> float sumSelectConfigs(
|
||||
List<T> selection,
|
||||
Map<T, Float> configs
|
||||
) {
|
||||
return sumSelectConfigs(selection, configs::get);
|
||||
}
|
||||
|
||||
public float sumSelectConfigs(
|
||||
List<SkeletonConfigOffsets> selection,
|
||||
SkeletonConfig config
|
||||
) {
|
||||
return sumSelectConfigs(selection, config::getOffset);
|
||||
}
|
||||
|
||||
public float getLengthSum(Map<BoneType, Float> configs) {
|
||||
return getLengthSum(configs, null);
|
||||
}
|
||||
|
||||
public float getLengthSum(
|
||||
Map<BoneType, Float> configs,
|
||||
Map<BoneType, Float> configsAlt
|
||||
) {
|
||||
float length = 0f;
|
||||
|
||||
if (configsAlt != null) {
|
||||
for (Entry<BoneType, Float> config : configsAlt.entrySet()) {
|
||||
// If there isn't a duplicate config
|
||||
if (!configs.containsKey(config.getKey())) {
|
||||
length += config.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Float boneLength : configs.values()) {
|
||||
length += boneLength;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public float getTargetHeight(PoseFrames frames) {
|
||||
float targetHeight;
|
||||
// Get the current skeleton from the server
|
||||
Skeleton skeleton = getSkeleton();
|
||||
if (skeleton != null) {
|
||||
// If there is a skeleton available, calculate the target height
|
||||
// from its configs
|
||||
targetHeight = sumSelectConfigs(legacyHeightConfigs, skeleton.getSkeletonConfig());
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Target height loaded from skeleton (Make sure you reset before running!): "
|
||||
+ targetHeight
|
||||
);
|
||||
} else {
|
||||
// Otherwise if there is no skeleton available, attempt to get the
|
||||
// max HMD height from the recording
|
||||
float hmdHeight = frames.getMaxHmdHeight();
|
||||
if (hmdHeight <= 0.50f) {
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): "
|
||||
+ hmdHeight
|
||||
);
|
||||
} else {
|
||||
LogManager.info("[AutoBone] Max headset height detected: " + hmdHeight);
|
||||
}
|
||||
|
||||
// Estimate target height from HMD height
|
||||
targetHeight = hmdHeight;
|
||||
}
|
||||
|
||||
return targetHeight;
|
||||
}
|
||||
|
||||
public AutoBoneResults processFrames(PoseFrames frames, Consumer<Epoch> epochCallback)
|
||||
throws AutoBoneException {
|
||||
return processFrames(frames, -1f, epochCallback);
|
||||
}
|
||||
|
||||
public AutoBoneResults processFrames(
|
||||
PoseFrames frames,
|
||||
float targetHeight,
|
||||
Consumer<Epoch> epochCallback
|
||||
) throws AutoBoneException {
|
||||
return processFrames(frames, true, targetHeight, epochCallback);
|
||||
}
|
||||
|
||||
public AutoBoneResults processFrames(
|
||||
PoseFrames frames,
|
||||
boolean calcInitError,
|
||||
float targetHeight,
|
||||
Consumer<Epoch> epochCallback
|
||||
) throws AutoBoneException {
|
||||
final int frameCount = frames.getMaxFrameCount();
|
||||
|
||||
List<PoseFrameTracker> trackers = frames.getTrackers();
|
||||
reloadConfigValues(trackers); // Reload configs and detect chest tracker
|
||||
// from the first frame
|
||||
|
||||
final PoseFrameSkeleton skeleton1 = new PoseFrameSkeleton(
|
||||
trackers,
|
||||
null
|
||||
);
|
||||
final PoseFrameSkeleton skeleton2 = new PoseFrameSkeleton(
|
||||
trackers,
|
||||
null
|
||||
);
|
||||
|
||||
EnumMap<BoneType, Float> intermediateOffsets = new EnumMap<>(
|
||||
offsets
|
||||
);
|
||||
|
||||
AutoBoneTrainingStep trainingStep = new AutoBoneTrainingStep(
|
||||
targetHeight,
|
||||
skeleton1,
|
||||
skeleton2,
|
||||
frames,
|
||||
intermediateOffsets
|
||||
);
|
||||
|
||||
skeleton1.setLegTweaksEnabled(false);
|
||||
skeleton2.setLegTweaksEnabled(false);
|
||||
|
||||
// If target height isn't specified, auto-detect
|
||||
if (targetHeight < 0f) {
|
||||
targetHeight = getTargetHeight(frames);
|
||||
}
|
||||
|
||||
StatsCalculator errorStats = new StatsCalculator();
|
||||
|
||||
// Epoch loop, each epoch is one full iteration over the full dataset
|
||||
for (int epoch = calcInitError ? -1 : 0; epoch < this.config.numEpochs; epoch++) {
|
||||
float adjustRate = epoch >= 0
|
||||
? (this.config.initialAdjustRate
|
||||
* FastMath.pow(this.config.adjustRateMultiplier, epoch))
|
||||
: 0f;
|
||||
|
||||
int[] randomFrameIndices = null;
|
||||
if (config.randomizeFrameOrder) {
|
||||
randomFrameIndices = new int[frameCount];
|
||||
|
||||
int zeroPos = -1;
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
int index = rand.nextInt(frameCount);
|
||||
|
||||
if (i > 0) {
|
||||
while (index == zeroPos || randomFrameIndices[index] > 0) {
|
||||
index = rand.nextInt(frameCount);
|
||||
}
|
||||
} else {
|
||||
zeroPos = index;
|
||||
}
|
||||
|
||||
randomFrameIndices[index] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the frames using a cursor and an offset for
|
||||
// comparing frames a
|
||||
// certain number of frames apart
|
||||
for (
|
||||
int cursorOffset = this.config.minDataDistance;
|
||||
cursorOffset <= this.config.maxDataDistance
|
||||
&& cursorOffset < frameCount;
|
||||
cursorOffset++
|
||||
) {
|
||||
for (
|
||||
int frameCursor = 0; frameCursor < frameCount - cursorOffset;
|
||||
frameCursor += config.cursorIncrement
|
||||
) {
|
||||
int frameCursor2 = frameCursor + cursorOffset;
|
||||
|
||||
applyConfig(skeleton1.skeletonConfig);
|
||||
skeleton2.skeletonConfig.setConfigs(skeleton1.skeletonConfig);
|
||||
|
||||
if (config.randomizeFrameOrder) {
|
||||
trainingStep
|
||||
.setCursors(
|
||||
randomFrameIndices[frameCursor],
|
||||
randomFrameIndices[frameCursor2]
|
||||
);
|
||||
} else {
|
||||
trainingStep.setCursors(frameCursor, frameCursor2);
|
||||
}
|
||||
|
||||
skeleton1.setCursor(trainingStep.getCursor1());
|
||||
skeleton2.setCursor(trainingStep.getCursor2());
|
||||
|
||||
skeleton1.updatePose();
|
||||
skeleton2.updatePose();
|
||||
|
||||
float totalLength = getLengthSum(offsets);
|
||||
float curHeight = sumSelectConfigs(heightOffsets, offsets);
|
||||
trainingStep.setCurrentHeight(curHeight);
|
||||
|
||||
float errorDeriv = getErrorDeriv(trainingStep);
|
||||
float error = errorFunc(errorDeriv);
|
||||
|
||||
// In case of fire
|
||||
if (Float.isNaN(error) || Float.isInfinite(error)) {
|
||||
// Extinguish
|
||||
LogManager
|
||||
.warning(
|
||||
"[AutoBone] Error value is invalid, resetting variables to recover"
|
||||
);
|
||||
reloadConfigValues(trackers);
|
||||
|
||||
// Reset error sum values
|
||||
errorStats.reset();
|
||||
|
||||
// Continue on new data
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store the error count for logging purposes
|
||||
errorStats.addValue(errorDeriv);
|
||||
|
||||
float adjustVal = error * adjustRate;
|
||||
|
||||
// If there is no adjustment whatsoever, skip this
|
||||
if (adjustVal == 0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3f slideLeft = skeleton2
|
||||
.getComputedTracker(TrackerRole.LEFT_FOOT).position
|
||||
.subtract(
|
||||
skeleton1.getComputedTracker(TrackerRole.LEFT_FOOT).position
|
||||
);
|
||||
|
||||
Vector3f slideRight = skeleton2
|
||||
.getComputedTracker(TrackerRole.RIGHT_FOOT).position
|
||||
.subtract(
|
||||
skeleton1
|
||||
.getComputedTracker(TrackerRole.RIGHT_FOOT).position
|
||||
);
|
||||
|
||||
intermediateOffsets.putAll(offsets);
|
||||
for (Entry<BoneType, Float> entry : offsets.entrySet()) {
|
||||
// Skip adjustment if the epoch is before starting (for
|
||||
// logging only)
|
||||
if (epoch < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
float originalLength = entry.getValue();
|
||||
boolean isHeightVar = heightOffsets.contains(entry.getKey());
|
||||
|
||||
float leftDotProduct = getDotProductDiff(
|
||||
skeleton1,
|
||||
skeleton2,
|
||||
entry.getKey(),
|
||||
false,
|
||||
slideLeft
|
||||
);
|
||||
|
||||
float rightDotProduct = getDotProductDiff(
|
||||
skeleton1,
|
||||
skeleton2,
|
||||
entry.getKey(),
|
||||
true,
|
||||
slideRight
|
||||
);
|
||||
|
||||
float dotLength = originalLength
|
||||
* ((leftDotProduct + rightDotProduct) / 2f);
|
||||
|
||||
// Scale by the ratio for smooth adjustment and more
|
||||
// stable results
|
||||
float curAdjustVal = (adjustVal * -dotLength) / totalLength;
|
||||
float newLength = originalLength + curAdjustVal;
|
||||
|
||||
// No small or negative numbers!!! Bad algorithm!
|
||||
if (newLength < 0.01f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply new offset length
|
||||
intermediateOffsets.put(entry.getKey(), newLength);
|
||||
applyConfig(skeleton1.skeletonConfig, intermediateOffsets);
|
||||
skeleton2.skeletonConfig.setConfigs(skeleton1.skeletonConfig);
|
||||
|
||||
// Update the skeleton poses for the new offset length
|
||||
skeleton1.updatePose();
|
||||
skeleton2.updatePose();
|
||||
|
||||
float newHeight = isHeightVar ? curHeight + curAdjustVal : curHeight;
|
||||
trainingStep.setCurrentHeight(newHeight);
|
||||
|
||||
float newErrorDeriv = getErrorDeriv(trainingStep);
|
||||
|
||||
if (newErrorDeriv < errorDeriv) {
|
||||
entry.setValue(newLength);
|
||||
}
|
||||
|
||||
// Reset the length to minimize bias in other variables,
|
||||
// it's applied later
|
||||
intermediateOffsets.put(entry.getKey(), originalLength);
|
||||
applyConfig(skeleton1.skeletonConfig, intermediateOffsets);
|
||||
skeleton2.skeletonConfig.setConfigs(skeleton1.skeletonConfig);
|
||||
}
|
||||
|
||||
if (config.scaleEachStep) {
|
||||
float stepHeight = sumSelectConfigs(heightOffsets, offsets);
|
||||
|
||||
if (stepHeight > 0f) {
|
||||
float stepHeightDiff = targetHeight - stepHeight;
|
||||
for (Entry<BoneType, Float> entry : offsets.entrySet()) {
|
||||
// Only height variables
|
||||
if (
|
||||
entry.getKey() == BoneType.NECK
|
||||
|| !heightOffsets.contains(entry.getKey())
|
||||
)
|
||||
continue;
|
||||
|
||||
float length = entry.getValue();
|
||||
|
||||
// Multiply the diff by the length to height
|
||||
// ratio
|
||||
float adjVal = stepHeightDiff * (length / stepHeight);
|
||||
|
||||
// Scale the length to fit the target height
|
||||
entry.setValue(Math.max(length + (adjVal / 2f), 0.01f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate average error over the epoch
|
||||
if (
|
||||
epoch <= 0
|
||||
|| epoch >= (config.numEpochs - 1)
|
||||
|| (epoch + 1) % config.printEveryNumEpochs == 0
|
||||
) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Epoch "
|
||||
+ (epoch + 1)
|
||||
+ " average error: "
|
||||
+ errorStats.getMean()
|
||||
+ " (SD "
|
||||
+ errorStats.getStandardDeviation()
|
||||
+ ")"
|
||||
);
|
||||
}
|
||||
|
||||
applyConfig(legacyConfigs);
|
||||
if (epochCallback != null) {
|
||||
epochCallback
|
||||
.accept(new Epoch(epoch + 1, this.config.numEpochs, errorStats, legacyConfigs));
|
||||
}
|
||||
}
|
||||
|
||||
float finalHeight = sumSelectConfigs(heightOffsets, offsets);
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Target height: "
|
||||
+ targetHeight
|
||||
+ " New height: "
|
||||
+ finalHeight
|
||||
);
|
||||
|
||||
return new AutoBoneResults(finalHeight, targetHeight, errorStats, legacyConfigs);
|
||||
}
|
||||
|
||||
protected float getErrorDeriv(AutoBoneTrainingStep trainingStep) throws AutoBoneException {
|
||||
float sumError = 0f;
|
||||
|
||||
if (this.config.slideErrorFactor > 0f) {
|
||||
sumError += slideError.getStepError(trainingStep) * this.config.slideErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.offsetSlideErrorFactor > 0f) {
|
||||
sumError += offsetSlideError.getStepError(trainingStep)
|
||||
* this.config.offsetSlideErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.footHeightOffsetErrorFactor > 0f) {
|
||||
sumError += footHeightOffsetError.getStepError(trainingStep)
|
||||
* this.config.footHeightOffsetErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.bodyProportionErrorFactor > 0f) {
|
||||
sumError += bodyProportionError.getStepError(trainingStep)
|
||||
* this.config.bodyProportionErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.heightErrorFactor > 0f) {
|
||||
sumError += heightError.getStepError(trainingStep) * this.config.heightErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.positionErrorFactor > 0f) {
|
||||
sumError += positionError.getStepError(trainingStep)
|
||||
* this.config.positionErrorFactor;
|
||||
}
|
||||
|
||||
if (this.config.positionOffsetErrorFactor > 0f) {
|
||||
sumError += positionOffsetError.getStepError(trainingStep)
|
||||
* this.config.positionOffsetErrorFactor;
|
||||
}
|
||||
|
||||
return sumError;
|
||||
}
|
||||
|
||||
public String getLengthsString() {
|
||||
final StringBuilder configInfo = new StringBuilder();
|
||||
this.offsets.forEach((key, value) -> {
|
||||
if (configInfo.length() > 0) {
|
||||
configInfo.append(", ");
|
||||
}
|
||||
|
||||
configInfo
|
||||
.append(key.toString())
|
||||
.append(": ")
|
||||
.append(StringUtils.prettyNumber(value * 100f, 2));
|
||||
});
|
||||
|
||||
return configInfo.toString();
|
||||
}
|
||||
|
||||
public void saveRecording(PoseFrames frames, File recordingFile) {
|
||||
if (saveDir.isDirectory() || saveDir.mkdirs()) {
|
||||
LogManager
|
||||
.info("[AutoBone] Exporting frames to \"" + recordingFile.getPath() + "\"...");
|
||||
if (PoseFrameIO.writeToFile(recordingFile, frames)) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Done exporting! Recording can be found at \""
|
||||
+ recordingFile.getPath()
|
||||
+ "\"."
|
||||
);
|
||||
} else {
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] Failed to export the recording to \""
|
||||
+ recordingFile.getPath()
|
||||
+ "\"."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] Failed to create the recording directory \""
|
||||
+ saveDir.getPath()
|
||||
+ "\"."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveRecording(PoseFrames frames, String recordingFileName) {
|
||||
saveRecording(frames, new File(saveDir, recordingFileName));
|
||||
}
|
||||
|
||||
public void saveRecording(PoseFrames frames) {
|
||||
File recordingFile;
|
||||
int recordingIndex = 1;
|
||||
do {
|
||||
recordingFile = new File(saveDir, "ABRecording" + recordingIndex++ + ".pfr");
|
||||
} while (recordingFile.exists());
|
||||
|
||||
saveRecording(frames, recordingFile);
|
||||
}
|
||||
|
||||
public List<Pair<String, PoseFrames>> loadRecordings() {
|
||||
List<Pair<String, PoseFrames>> recordings = new FastList<>();
|
||||
if (loadDir.isDirectory()) {
|
||||
File[] files = loadDir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (
|
||||
file.isFile()
|
||||
&& org.apache.commons.lang3.StringUtils
|
||||
.endsWithIgnoreCase(file.getName(), ".pfr")
|
||||
) {
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Detected recording at \""
|
||||
+ file.getPath()
|
||||
+ "\", loading frames..."
|
||||
);
|
||||
PoseFrames frames = PoseFrameIO.readFromFile(file);
|
||||
|
||||
if (frames == null) {
|
||||
LogManager
|
||||
.severe("Reading frames from \"" + file.getPath() + "\" failed...");
|
||||
} else {
|
||||
recordings.add(Pair.of(file.getName(), frames));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return recordings;
|
||||
}
|
||||
|
||||
public AutoBoneConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public class Epoch {
|
||||
|
||||
public final int epoch;
|
||||
public final int totalEpochs;
|
||||
public final StatsCalculator epochError;
|
||||
public final EnumMap<SkeletonConfigOffsets, Float> configValues;
|
||||
|
||||
public Epoch(
|
||||
int epoch,
|
||||
int totalEpochs,
|
||||
StatsCalculator epochError,
|
||||
EnumMap<SkeletonConfigOffsets, Float> configValues
|
||||
) {
|
||||
this.epoch = epoch;
|
||||
this.totalEpochs = totalEpochs;
|
||||
this.epochError = epochError;
|
||||
this.configValues = configValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Epoch: " + epoch + ", Epoch Error: " + epochError;
|
||||
}
|
||||
}
|
||||
|
||||
public class AutoBoneResults {
|
||||
|
||||
public final float finalHeight;
|
||||
public final float targetHeight;
|
||||
public final StatsCalculator epochError;
|
||||
public final EnumMap<SkeletonConfigOffsets, Float> configValues;
|
||||
|
||||
public AutoBoneResults(
|
||||
float finalHeight,
|
||||
float targetHeight,
|
||||
StatsCalculator epochError,
|
||||
EnumMap<SkeletonConfigOffsets, Float> configValues
|
||||
) {
|
||||
this.finalHeight = finalHeight;
|
||||
this.targetHeight = targetHeight;
|
||||
this.epochError = epochError;
|
||||
this.configValues = configValues;
|
||||
}
|
||||
|
||||
public float getHeightDifference() {
|
||||
return FastMath.abs(targetHeight - finalHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
434
src/main/java/dev/slimevr/autobone/AutoBoneHandler.java
Normal file
434
src/main/java/dev/slimevr/autobone/AutoBoneHandler.java
Normal file
@@ -0,0 +1,434 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.autobone.AutoBone.AutoBoneResults;
|
||||
import dev.slimevr.autobone.errors.AutoBoneException;
|
||||
import dev.slimevr.poserecorder.PoseFrameTracker;
|
||||
import dev.slimevr.poserecorder.PoseFrames;
|
||||
import dev.slimevr.poserecorder.PoseRecorder;
|
||||
import dev.slimevr.poserecorder.TrackerFrame;
|
||||
import dev.slimevr.poserecorder.TrackerFrameData;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfig;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigOffsets;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
public class AutoBoneHandler {
|
||||
|
||||
private final VRServer server;
|
||||
private final PoseRecorder poseRecorder;
|
||||
private final AutoBone autoBone;
|
||||
|
||||
private ReentrantLock recordingLock = new ReentrantLock();
|
||||
private Thread recordingThread = null;
|
||||
|
||||
private ReentrantLock saveRecordingLock = new ReentrantLock();
|
||||
private Thread saveRecordingThread = null;
|
||||
|
||||
private ReentrantLock autoBoneLock = new ReentrantLock();
|
||||
private Thread autoBoneThread = null;
|
||||
|
||||
private List<AutoBoneListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public AutoBoneHandler(VRServer server) {
|
||||
this.server = server;
|
||||
this.poseRecorder = new PoseRecorder(server);
|
||||
this.autoBone = new AutoBone(server);
|
||||
}
|
||||
|
||||
public void addListener(AutoBoneListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(AutoBoneListener listener) {
|
||||
this.listeners.removeIf(l -> listener == l);
|
||||
}
|
||||
|
||||
private void announceProcessStatus(
|
||||
AutoBoneProcessType processType,
|
||||
String message,
|
||||
long current,
|
||||
long total,
|
||||
boolean completed,
|
||||
boolean success
|
||||
) {
|
||||
listeners
|
||||
.forEach(
|
||||
listener -> listener
|
||||
.onAutoBoneProcessStatus(
|
||||
processType,
|
||||
message,
|
||||
current,
|
||||
total,
|
||||
completed,
|
||||
success
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void announceProcessStatus(
|
||||
AutoBoneProcessType processType,
|
||||
String message,
|
||||
boolean completed,
|
||||
boolean success
|
||||
) {
|
||||
announceProcessStatus(processType, message, 0, 0, completed, success);
|
||||
}
|
||||
|
||||
private void announceProcessStatus(AutoBoneProcessType processType, String message) {
|
||||
announceProcessStatus(processType, message, false, true);
|
||||
}
|
||||
|
||||
private void announceProcessStatus(AutoBoneProcessType processType, long current, long total) {
|
||||
announceProcessStatus(processType, null, current, total, false, true);
|
||||
}
|
||||
|
||||
public String getLengthsString() {
|
||||
return autoBone.getLengthsString();
|
||||
}
|
||||
|
||||
private AutoBoneResults processFrames(PoseFrames frames) throws AutoBoneException {
|
||||
return autoBone
|
||||
.processFrames(
|
||||
frames,
|
||||
autoBone.getConfig().calcInitError,
|
||||
autoBone.getConfig().targetHeight,
|
||||
(epoch) -> listeners.forEach(listener -> listener.onAutoBoneEpoch(epoch))
|
||||
);
|
||||
}
|
||||
|
||||
public boolean startProcessByType(AutoBoneProcessType processType) {
|
||||
switch (processType) {
|
||||
case RECORD:
|
||||
startRecording();
|
||||
break;
|
||||
|
||||
case SAVE:
|
||||
saveRecording();
|
||||
break;
|
||||
|
||||
case PROCESS:
|
||||
processRecording();
|
||||
break;
|
||||
|
||||
case APPLY:
|
||||
applyValues();
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void startRecording() {
|
||||
recordingLock.lock();
|
||||
|
||||
try {
|
||||
// Prevent running multiple times
|
||||
if (recordingThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread(this::startRecordingThread);
|
||||
recordingThread = thread;
|
||||
thread.start();
|
||||
} finally {
|
||||
recordingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void startRecordingThread() {
|
||||
try {
|
||||
if (poseRecorder.isReadyToRecord()) {
|
||||
announceProcessStatus(AutoBoneProcessType.RECORD, "Recording...");
|
||||
|
||||
// 1000 samples at 20 ms per sample is 20 seconds
|
||||
int sampleCount = this.autoBone.getConfig().sampleCount;
|
||||
long sampleRate = this.autoBone.getConfig().sampleRateMs;
|
||||
Future<PoseFrames> framesFuture = poseRecorder
|
||||
.startFrameRecording(
|
||||
sampleCount,
|
||||
sampleRate,
|
||||
progress -> announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
progress.frame,
|
||||
progress.totalFrames
|
||||
)
|
||||
);
|
||||
PoseFrames frames = framesFuture.get();
|
||||
LogManager.info("[AutoBone] Done recording!");
|
||||
|
||||
// Save a recurring recording for users to send as debug info
|
||||
announceProcessStatus(AutoBoneProcessType.RECORD, "Saving recording...");
|
||||
autoBone.saveRecording(frames, "LastABRecording.pfr");
|
||||
|
||||
if (this.autoBone.getConfig().saveRecordings) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
"Saving recording (from config option)..."
|
||||
);
|
||||
autoBone.saveRecording(frames);
|
||||
}
|
||||
|
||||
listeners.forEach(listener -> listener.onAutoBoneRecordingEnd(frames));
|
||||
|
||||
announceProcessStatus(AutoBoneProcessType.RECORD, "Done recording!", true, true);
|
||||
} else {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
"The server is not ready to record",
|
||||
true,
|
||||
false
|
||||
);
|
||||
LogManager.severe("[AutoBone] Unable to record...");
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.RECORD,
|
||||
String.format("Recording failed: %s", e.getMessage()),
|
||||
true,
|
||||
false
|
||||
);
|
||||
LogManager.severe("[AutoBone] Failed recording!", e);
|
||||
} finally {
|
||||
recordingThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void saveRecording() {
|
||||
saveRecordingLock.lock();
|
||||
|
||||
try {
|
||||
// Prevent running multiple times
|
||||
if (saveRecordingThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread(this::saveRecordingThread);
|
||||
saveRecordingThread = thread;
|
||||
thread.start();
|
||||
} finally {
|
||||
saveRecordingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveRecordingThread() {
|
||||
try {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
announceProcessStatus(AutoBoneProcessType.SAVE, "Waiting for recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
|
||||
announceProcessStatus(AutoBoneProcessType.SAVE, "Saving recording...");
|
||||
autoBone.saveRecording(frames);
|
||||
|
||||
announceProcessStatus(AutoBoneProcessType.SAVE, "Recording saved!", true, true);
|
||||
} else {
|
||||
announceProcessStatus(AutoBoneProcessType.SAVE, "No recording found", true, false);
|
||||
LogManager.severe("[AutoBone] Unable to save, no recording was done...");
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.SAVE,
|
||||
String.format("Failed to save recording: %s", e.getMessage()),
|
||||
true,
|
||||
false
|
||||
);
|
||||
LogManager.severe("[AutoBone] Failed to save recording!", e);
|
||||
} finally {
|
||||
saveRecordingThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void processRecording() {
|
||||
autoBoneLock.lock();
|
||||
|
||||
try {
|
||||
// Prevent running multiple times
|
||||
if (autoBoneThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread(this::processRecordingThread);
|
||||
autoBoneThread = thread;
|
||||
thread.start();
|
||||
} finally {
|
||||
autoBoneLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void processRecordingThread() {
|
||||
try {
|
||||
announceProcessStatus(AutoBoneProcessType.PROCESS, "Loading recordings...");
|
||||
List<Pair<String, PoseFrames>> frameRecordings = autoBone.loadRecordings();
|
||||
|
||||
if (!frameRecordings.isEmpty()) {
|
||||
LogManager.info("[AutoBone] Done loading frames!");
|
||||
} else {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
announceProcessStatus(AutoBoneProcessType.PROCESS, "Waiting for recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
|
||||
frameRecordings.add(Pair.of("<Recording>", frames));
|
||||
} else {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.PROCESS,
|
||||
"No recordings found...",
|
||||
true,
|
||||
false
|
||||
);
|
||||
LogManager
|
||||
.severe(
|
||||
"[AutoBone] No recordings found in \""
|
||||
+ AutoBone.getLoadDir().getPath()
|
||||
+ "\" and no recording was done..."
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
announceProcessStatus(AutoBoneProcessType.PROCESS, "Processing recording(s)...");
|
||||
LogManager.info("[AutoBone] Processing frames...");
|
||||
StatsCalculator errorStats = new StatsCalculator();
|
||||
SkeletonConfig skeletonConfigBuffer = new SkeletonConfig(false);
|
||||
for (Pair<String, PoseFrames> recording : frameRecordings) {
|
||||
LogManager
|
||||
.info("[AutoBone] Processing frames from \"" + recording.getKey() + "\"...");
|
||||
|
||||
List<PoseFrameTracker> trackers = recording.getValue().getTrackers();
|
||||
|
||||
StringBuilder trackerInfo = new StringBuilder();
|
||||
for (PoseFrameTracker tracker : trackers) {
|
||||
if (tracker == null)
|
||||
continue;
|
||||
|
||||
TrackerFrame frame = tracker.safeGetFrame(0);
|
||||
if (frame == null || !frame.hasData(TrackerFrameData.DESIGNATION))
|
||||
continue;
|
||||
|
||||
if (trackerInfo.length() > 0) {
|
||||
trackerInfo.append(", ");
|
||||
}
|
||||
|
||||
trackerInfo.append(frame.designation.designation);
|
||||
|
||||
if (frame.hasData(TrackerFrameData.POSITION)) {
|
||||
trackerInfo.append(" (P)");
|
||||
}
|
||||
}
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] ("
|
||||
+ trackers.size()
|
||||
+ " trackers) ["
|
||||
+ trackerInfo
|
||||
+ "]"
|
||||
);
|
||||
|
||||
AutoBoneResults autoBoneResults = processFrames(recording.getValue());
|
||||
errorStats.addValue(autoBoneResults.getHeightDifference());
|
||||
LogManager.info("[AutoBone] Done processing!");
|
||||
|
||||
// #region Stats/Values
|
||||
skeletonConfigBuffer.setConfigs(autoBoneResults.configValues, null, null);
|
||||
|
||||
float neckLength = skeletonConfigBuffer.getOffset(SkeletonConfigOffsets.NECK);
|
||||
float chestDistance = skeletonConfigBuffer
|
||||
.getOffset(SkeletonConfigOffsets.CHEST);
|
||||
float torsoLength = skeletonConfigBuffer
|
||||
.getOffset(SkeletonConfigOffsets.TORSO);
|
||||
float hipWidth = skeletonConfigBuffer
|
||||
.getOffset(SkeletonConfigOffsets.HIPS_WIDTH);
|
||||
float legsLength = skeletonConfigBuffer
|
||||
.getOffset(SkeletonConfigOffsets.LEGS_LENGTH);
|
||||
float kneeHeight = skeletonConfigBuffer
|
||||
.getOffset(SkeletonConfigOffsets.KNEE_HEIGHT);
|
||||
|
||||
float neckTorso = neckLength / torsoLength;
|
||||
float chestTorso = chestDistance / torsoLength;
|
||||
float torsoWaist = hipWidth / torsoLength;
|
||||
float legTorso = legsLength / torsoLength;
|
||||
float legBody = legsLength / (torsoLength + neckLength);
|
||||
float kneeLeg = kneeHeight / legsLength;
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Ratios: [{Neck-Torso: "
|
||||
+ StringUtils.prettyNumber(neckTorso)
|
||||
+ "}, {Chest-Torso: "
|
||||
+ StringUtils.prettyNumber(chestTorso)
|
||||
+ "}, {Torso-Waist: "
|
||||
+ StringUtils.prettyNumber(torsoWaist)
|
||||
+ "}, {Leg-Torso: "
|
||||
+ StringUtils.prettyNumber(legTorso)
|
||||
+ "}, {Leg-Body: "
|
||||
+ StringUtils.prettyNumber(legBody)
|
||||
+ "}, {Knee-Leg: "
|
||||
+ StringUtils.prettyNumber(kneeLeg)
|
||||
+ "}]"
|
||||
);
|
||||
LogManager.info("[AutoBone] Length values: " + autoBone.getLengthsString());
|
||||
}
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[AutoBone] Average height error: "
|
||||
+ StringUtils.prettyNumber(errorStats.getMean(), 6)
|
||||
+ " (SD "
|
||||
+ StringUtils.prettyNumber(errorStats.getStandardDeviation(), 6)
|
||||
+ ")"
|
||||
);
|
||||
// #endregion
|
||||
|
||||
listeners.forEach(listener -> listener.onAutoBoneEnd(autoBone.legacyConfigs));
|
||||
|
||||
announceProcessStatus(AutoBoneProcessType.PROCESS, "Done processing!", true, true);
|
||||
} catch (Exception e) {
|
||||
announceProcessStatus(
|
||||
AutoBoneProcessType.PROCESS,
|
||||
String.format("Processing failed: %s", e.getMessage()),
|
||||
true,
|
||||
false
|
||||
);
|
||||
LogManager.severe("[AutoBone] Failed adjustment!", e);
|
||||
} finally {
|
||||
autoBoneThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void applyValues() {
|
||||
autoBone.applyAndSaveConfig();
|
||||
announceProcessStatus(AutoBoneProcessType.APPLY, "Adjusted values applied!", true, true);
|
||||
// TODO Update GUI values after applying? Is that needed here?
|
||||
}
|
||||
|
||||
}
|
||||
26
src/main/java/dev/slimevr/autobone/AutoBoneListener.java
Normal file
26
src/main/java/dev/slimevr/autobone/AutoBoneListener.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
import dev.slimevr.autobone.AutoBone.Epoch;
|
||||
import dev.slimevr.poserecorder.PoseFrames;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigOffsets;
|
||||
|
||||
|
||||
public interface AutoBoneListener {
|
||||
|
||||
void onAutoBoneProcessStatus(
|
||||
AutoBoneProcessType processType,
|
||||
String message,
|
||||
long current,
|
||||
long total,
|
||||
boolean completed,
|
||||
boolean success
|
||||
);
|
||||
|
||||
void onAutoBoneRecordingEnd(PoseFrames recording);
|
||||
|
||||
void onAutoBoneEpoch(Epoch epoch);
|
||||
|
||||
void onAutoBoneEnd(EnumMap<SkeletonConfigOffsets, Float> configValues);
|
||||
}
|
||||
31
src/main/java/dev/slimevr/autobone/AutoBoneProcessType.java
Normal file
31
src/main/java/dev/slimevr/autobone/AutoBoneProcessType.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public enum AutoBoneProcessType {
|
||||
NONE(0),
|
||||
RECORD(1),
|
||||
SAVE(2),
|
||||
PROCESS(3),
|
||||
APPLY(4);
|
||||
|
||||
public final int id;
|
||||
|
||||
private static final Map<Integer, AutoBoneProcessType> byId = new HashMap<>();
|
||||
|
||||
AutoBoneProcessType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static AutoBoneProcessType getById(int id) {
|
||||
return byId.get(id);
|
||||
}
|
||||
|
||||
static {
|
||||
for (AutoBoneProcessType abpt : values()) {
|
||||
byId.put(abpt.id, abpt);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/main/java/dev/slimevr/autobone/AutoBoneTrainingStep.java
Normal file
108
src/main/java/dev/slimevr/autobone/AutoBoneTrainingStep.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import dev.slimevr.poserecorder.PoseFrameSkeleton;
|
||||
import dev.slimevr.poserecorder.PoseFrames;
|
||||
import dev.slimevr.vr.processor.skeleton.BoneType;
|
||||
|
||||
|
||||
public class AutoBoneTrainingStep {
|
||||
private int cursor1 = 0;
|
||||
private int cursor2 = 0;
|
||||
|
||||
private float currentHeight;
|
||||
private final float targetHeight;
|
||||
|
||||
private final PoseFrameSkeleton skeleton1;
|
||||
private final PoseFrameSkeleton skeleton2;
|
||||
|
||||
private final PoseFrames trainingFrames;
|
||||
|
||||
private final Map<BoneType, Float> intermediateOffsets;
|
||||
|
||||
public AutoBoneTrainingStep(
|
||||
int cursor1,
|
||||
int cursor2,
|
||||
float targetHeight,
|
||||
PoseFrameSkeleton skeleton1,
|
||||
PoseFrameSkeleton skeleton2,
|
||||
PoseFrames trainingFrames,
|
||||
Map<BoneType, Float> intermediateOffsets
|
||||
) {
|
||||
this.cursor1 = cursor1;
|
||||
this.cursor2 = cursor2;
|
||||
this.targetHeight = targetHeight;
|
||||
this.skeleton1 = skeleton1;
|
||||
this.skeleton2 = skeleton2;
|
||||
this.trainingFrames = trainingFrames;
|
||||
this.intermediateOffsets = intermediateOffsets;
|
||||
}
|
||||
|
||||
public AutoBoneTrainingStep(
|
||||
float targetHeight,
|
||||
PoseFrameSkeleton skeleton1,
|
||||
PoseFrameSkeleton skeleton2,
|
||||
PoseFrames trainingFrames,
|
||||
Map<BoneType, Float> intermediateOffsets
|
||||
) {
|
||||
this.targetHeight = targetHeight;
|
||||
this.skeleton1 = skeleton1;
|
||||
this.skeleton2 = skeleton2;
|
||||
this.trainingFrames = trainingFrames;
|
||||
this.intermediateOffsets = intermediateOffsets;
|
||||
}
|
||||
|
||||
public int getCursor1() {
|
||||
return cursor1;
|
||||
}
|
||||
|
||||
public void setCursor1(int cursor1) {
|
||||
this.cursor1 = cursor1;
|
||||
}
|
||||
|
||||
public int getCursor2() {
|
||||
return cursor2;
|
||||
}
|
||||
|
||||
public void setCursor2(int cursor2) {
|
||||
this.cursor2 = cursor2;
|
||||
}
|
||||
|
||||
public void setCursors(int cursor1, int cursor2) {
|
||||
this.cursor1 = cursor1;
|
||||
this.cursor2 = cursor2;
|
||||
}
|
||||
|
||||
public float getCurrentHeight() {
|
||||
return currentHeight;
|
||||
}
|
||||
|
||||
public void setCurrentHeight(float currentHeight) {
|
||||
this.currentHeight = currentHeight;
|
||||
}
|
||||
|
||||
public float getTargetHeight() {
|
||||
return targetHeight;
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton getSkeleton1() {
|
||||
return skeleton1;
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton getSkeleton2() {
|
||||
return skeleton2;
|
||||
}
|
||||
|
||||
public PoseFrames getTrainingFrames() {
|
||||
return trainingFrames;
|
||||
}
|
||||
|
||||
public Map<BoneType, Float> getIntermediateOffsets() {
|
||||
return intermediateOffsets;
|
||||
}
|
||||
|
||||
public float getHeightOffset() {
|
||||
return getTargetHeight() - getCurrentHeight();
|
||||
}
|
||||
}
|
||||
51
src/main/java/dev/slimevr/autobone/StatsCalculator.java
Normal file
51
src/main/java/dev/slimevr/autobone/StatsCalculator.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package dev.slimevr.autobone;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
|
||||
|
||||
/// This is a stat calculator based on Welford's online algorithm
|
||||
/// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
|
||||
public class StatsCalculator {
|
||||
|
||||
private int count = 0;
|
||||
private float mean = 0f;
|
||||
private float M2 = 0f;
|
||||
|
||||
public void reset() {
|
||||
count = 0;
|
||||
mean = 0f;
|
||||
M2 = 0f;
|
||||
}
|
||||
|
||||
public void addValue(float newValue) {
|
||||
count += 1;
|
||||
float delta = newValue - mean;
|
||||
mean += delta / count;
|
||||
float delta2 = newValue - mean;
|
||||
M2 += delta * delta2;
|
||||
}
|
||||
|
||||
public float getMean() {
|
||||
return mean;
|
||||
}
|
||||
|
||||
public float getVariance() {
|
||||
if (count < 1) {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
return M2 / count;
|
||||
}
|
||||
|
||||
public float getSampleVariance() {
|
||||
if (count < 2) {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
return M2 / (count - 1);
|
||||
}
|
||||
|
||||
public float getStandardDeviation() {
|
||||
return FastMath.sqrt(getVariance());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user