Compare commits
1838 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba75777c0d | ||
|
|
92c0b4493a | ||
|
|
803231c558 | ||
|
|
120909f8d6 | ||
|
|
f0f23cbd0b | ||
|
|
939a35ee97 | ||
|
|
18e1785e57 | ||
|
|
bef2709834 | ||
|
|
c063e2fc30 | ||
|
|
6e62ce15b5 | ||
|
|
19221e1fcc | ||
|
|
c25d6cb551 | ||
|
|
86920a3083 | ||
|
|
68c39290ec | ||
|
|
563f56d2a2 | ||
|
|
4174333b40 | ||
|
|
a74445f9e4 | ||
|
|
859d8cc86c | ||
|
|
d8d2f1c801 | ||
|
|
85308462eb | ||
|
|
d84f8b14c4 | ||
|
|
0f4889923d | ||
|
|
2093816f2d | ||
|
|
7de751f882 | ||
|
|
6da476aebb | ||
|
|
7140d25a87 | ||
|
|
cb413a99f0 | ||
|
|
e6d21518d2 | ||
|
|
19e647ae84 | ||
|
|
494f5c71bb | ||
|
|
c4ad80f3b9 | ||
|
|
460fa6c8e6 | ||
|
|
5a62ffe178 | ||
|
|
c867d7bdf2 | ||
|
|
167cf7c659 | ||
|
|
73a3ec3f63 | ||
|
|
f8981248dc | ||
|
|
b90b2469b5 | ||
|
|
2de9ca144d | ||
|
|
f1a89a1c55 | ||
|
|
3909aa4ab7 | ||
|
|
10e95f5388 | ||
|
|
21bb2af7ea | ||
|
|
9b7b4071bf | ||
|
|
2ec267fc4f | ||
|
|
e6b954e9e8 | ||
|
|
b2ce0f3934 | ||
|
|
01d3a91e40 | ||
|
|
cf0b87298d | ||
|
|
02c69c1686 | ||
|
|
9a53ffa6d0 | ||
|
|
d22e23937f | ||
|
|
7b820e10e0 | ||
|
|
d795fee579 | ||
|
|
80418162d4 | ||
|
|
32c83a6eee | ||
|
|
d0b8cf0275 | ||
|
|
74fa6da8c2 | ||
|
|
f199f96f7b | ||
|
|
bfc13549e9 | ||
|
|
7660b07fa8 | ||
|
|
b72054c2f7 | ||
|
|
9dcbc38231 | ||
|
|
dbb50cf580 | ||
|
|
da0782d036 | ||
|
|
778801992d | ||
|
|
f410ff0ed2 | ||
|
|
23685253a8 | ||
|
|
21ad2cab07 | ||
|
|
c5a14422ee | ||
|
|
c12deb4b56 | ||
|
|
792d98dfd5 | ||
|
|
12aa3b19d5 | ||
|
|
4b3f782ece | ||
|
|
0016a41474 | ||
|
|
e115981b9f | ||
|
|
94fbe58fb7 | ||
|
|
90962d0391 | ||
|
|
7092de8809 | ||
|
|
81a0a724ab | ||
|
|
34297feed4 | ||
|
|
4407f8ac68 | ||
|
|
3de691fa0d | ||
|
|
e7f388999d | ||
|
|
8d66913a8e | ||
|
|
b30b5b6474 | ||
|
|
19b8412d67 | ||
|
|
24d2555c5e | ||
|
|
322564bc42 | ||
|
|
12bff7aa9e | ||
|
|
d87a84db85 | ||
|
|
b38017eb1c | ||
|
|
2d99870ec2 | ||
|
|
6f7a4aa234 | ||
|
|
49add7e0f8 | ||
|
|
c2708078db | ||
|
|
a46e68f145 | ||
|
|
a4f8d46d69 | ||
|
|
94d6bc4bca | ||
|
|
ec78631691 | ||
|
|
cd8f9792ab | ||
|
|
fd9c868c40 | ||
|
|
6282500305 | ||
|
|
7b5bc6d236 | ||
|
|
3e45ec7353 | ||
|
|
5051f4e38c | ||
|
|
5532e3349a | ||
|
|
4ea7a09583 | ||
|
|
affba5a29f | ||
|
|
d486055fc8 | ||
|
|
52b7cd68c1 | ||
|
|
afdf4bf108 | ||
|
|
a33dbac984 | ||
|
|
ff48107b1a | ||
|
|
3afaaed1fb | ||
|
|
7ca6299fba | ||
|
|
cba7f5b801 | ||
|
|
d75ed8aeee | ||
|
|
b9b2984235 | ||
|
|
c2b7892e6c | ||
|
|
6ce07c0a4b | ||
|
|
008e217a79 | ||
|
|
5847e52fbc | ||
|
|
e9baa25b46 | ||
|
|
b6213e1ed8 | ||
|
|
59ac3a0bb8 | ||
|
|
9b63972878 | ||
|
|
4955e24f12 | ||
|
|
16fb654b98 | ||
|
|
eda88b3078 | ||
|
|
2435277e49 | ||
|
|
7caded7c95 | ||
|
|
df6cdf9a80 | ||
|
|
25be63ef2c | ||
|
|
b0a042369f | ||
|
|
d8d68dcf71 | ||
|
|
133fb661b3 | ||
|
|
d5f2b375a6 | ||
|
|
f280d3b64c | ||
|
|
e20261fa66 | ||
|
|
b6a41d417d | ||
|
|
80f3052c2b | ||
|
|
62060e0c04 | ||
|
|
f3f7c57f10 | ||
|
|
82d61909f6 | ||
|
|
03c68d1dc3 | ||
|
|
05f593e40c | ||
|
|
5719c6cfc2 | ||
|
|
1ba8ff06e1 | ||
|
|
fae5d09001 | ||
|
|
3eecb412c6 | ||
|
|
b022be49a1 | ||
|
|
7238eccfd2 | ||
|
|
e3b8ccff9e | ||
|
|
c1aa3c9d4d | ||
|
|
00345c94a3 | ||
|
|
20001e6a26 | ||
|
|
c06fdc7760 | ||
|
|
8e28eba959 | ||
|
|
47ff1a2dd8 | ||
|
|
00ff0f532f | ||
|
|
2e0732c75b | ||
|
|
842247de54 | ||
|
|
52840ce8ae | ||
|
|
f640d2574b | ||
|
|
8598aad9e2 | ||
|
|
5dc82aadc7 | ||
|
|
2f8411a658 | ||
|
|
fcce9b62d5 | ||
|
|
5a077d2f52 | ||
|
|
36f8ea8df0 | ||
|
|
fe623d93a1 | ||
|
|
d41b8a7c24 | ||
|
|
f016a82a32 | ||
|
|
d872aa4a6c | ||
|
|
2c7262ced4 | ||
|
|
01e21ea212 | ||
|
|
0eae04ab83 | ||
|
|
e42afcb434 | ||
|
|
fad4be419a | ||
|
|
9768d17b9b | ||
|
|
e36bae2ab6 | ||
|
|
f8b5b1db9c | ||
|
|
9ccf1a31bc | ||
|
|
36d23b5dc2 | ||
|
|
9d27335d7d | ||
|
|
a913cee7a4 | ||
|
|
eeeba3d2b7 | ||
|
|
b8a56776da | ||
|
|
0e9fe58c06 | ||
|
|
6cf7635005 | ||
|
|
6c7ea3a16d | ||
|
|
4ded0d03d0 | ||
|
|
ac45ad740d | ||
|
|
f010c840e6 | ||
|
|
90b59908c6 | ||
|
|
13c6693cdd | ||
|
|
cd56c960a6 | ||
|
|
a51423a4d6 | ||
|
|
80a25ec71c | ||
|
|
51209179d1 | ||
|
|
b3937caa10 | ||
|
|
8927ba7c73 | ||
|
|
5f4c867618 | ||
|
|
fced4178be | ||
|
|
da0944c814 | ||
|
|
7aa14219b8 | ||
|
|
09a3494183 | ||
|
|
8924d81e0a | ||
|
|
b599fbf88d | ||
|
|
578a72f560 | ||
|
|
6b1e298d43 | ||
|
|
698665c4cc | ||
|
|
caa3e4d07a | ||
|
|
7606baa20b | ||
|
|
fde6be3f97 | ||
|
|
abdc70121d | ||
|
|
879a0524fc | ||
|
|
a529b34f99 | ||
|
|
e8daeb5f30 | ||
|
|
f610e8ba1e | ||
|
|
b3245c967b | ||
|
|
0af9da2214 | ||
|
|
db68f80048 | ||
|
|
b0efd80e42 | ||
|
|
3e12e0b84d | ||
|
|
5465a45dc6 | ||
|
|
53bd7d6ae2 | ||
|
|
d66751b6ac | ||
|
|
95de6d0afc | ||
|
|
147daa7681 | ||
|
|
ece925858a | ||
|
|
657b05d077 | ||
|
|
cf3bceeb46 | ||
|
|
6735e5eaaa | ||
|
|
7b9e71df40 | ||
|
|
fae61f3d87 | ||
|
|
a57419150e | ||
|
|
378257b7bf | ||
|
|
885b92a0a1 | ||
|
|
58371c36d3 | ||
|
|
d39064b209 | ||
|
|
f497da7967 | ||
|
|
03931cb232 | ||
|
|
4eeb02d9d4 | ||
|
|
8ff5ae3555 | ||
|
|
053a5e9dbe | ||
|
|
5a1a88bf33 | ||
|
|
f19b18d806 | ||
|
|
f6e4701d6b | ||
|
|
c3d686e472 | ||
|
|
6c7ff870e8 | ||
|
|
38bac83ddd | ||
|
|
4d8c77cf3e | ||
|
|
0a147697d2 | ||
|
|
21837e7464 | ||
|
|
d747962e24 | ||
|
|
49f09d1b3a | ||
|
|
783d6e69b1 | ||
|
|
6452ff78c0 | ||
|
|
a430d39849 | ||
|
|
33c222555f | ||
|
|
00f7e0fe62 | ||
|
|
44a31ede74 | ||
|
|
fb3ee2aa8c | ||
|
|
58e5dd9186 | ||
|
|
27ec46c64e | ||
|
|
12a5d777e5 | ||
|
|
276a94f9e8 | ||
|
|
ccc3c86900 | ||
|
|
124415363f | ||
|
|
de850b39f2 | ||
|
|
379f73b6ca | ||
|
|
159b778fa9 | ||
|
|
007f7a0ce1 | ||
|
|
54fa642693 | ||
|
|
2fbc6f9193 | ||
|
|
262c6fd8ab | ||
|
|
7fcb53c7d0 | ||
|
|
d0e1101bfb | ||
|
|
a8bb4ae6d1 | ||
|
|
d743307e59 | ||
|
|
e92e9eb45c | ||
|
|
aaefa356ae | ||
|
|
3a7da2bc98 | ||
|
|
94b211e3b7 | ||
|
|
9ff5b90605 | ||
|
|
a033b74f7f | ||
|
|
bb4e81b00a | ||
|
|
5f2e0b79cd | ||
|
|
64a7fef7c1 | ||
|
|
09dbc5c84e | ||
|
|
e71e0791bc | ||
|
|
2a4be39c9a | ||
|
|
3cde191afb | ||
|
|
02a8d9a243 | ||
|
|
7f4e313a78 | ||
|
|
44e3d90dcb | ||
|
|
945eb3ccc6 | ||
|
|
793008852a | ||
|
|
7e791ee5e4 | ||
|
|
1413490579 | ||
|
|
57154e5d0b | ||
|
|
57a1556e23 | ||
|
|
e248e92ca1 | ||
|
|
fa5adcf08b | ||
|
|
87a51afd99 | ||
|
|
4efaa1f350 | ||
|
|
1d329600af | ||
|
|
c2a0e51984 | ||
|
|
ebd59e38ce | ||
|
|
f75b384c17 | ||
|
|
5419622c74 | ||
|
|
ab40011954 | ||
|
|
1b658e9b40 | ||
|
|
49605f9c23 | ||
|
|
d9b6b808f7 | ||
|
|
1607dd329d | ||
|
|
74337b2699 | ||
|
|
d6a684bbe7 | ||
|
|
feeb997f62 | ||
|
|
26da3bf9a8 | ||
|
|
82046afd9f | ||
|
|
97704deea0 | ||
|
|
64b2a18ff3 | ||
|
|
cf16edceec | ||
|
|
f6008737d1 | ||
|
|
61de8c4717 | ||
|
|
83ad83e656 | ||
|
|
2afb13c580 | ||
|
|
e48a963503 | ||
|
|
c846a0626f | ||
|
|
a6b1d09ff1 | ||
|
|
3603e146cc | ||
|
|
9ab597c0e9 | ||
|
|
3251e9f845 | ||
|
|
3e7b24a3de | ||
|
|
6989cd4d40 | ||
|
|
c7205a512e | ||
|
|
c0befa0f49 | ||
|
|
2223024383 | ||
|
|
216d9a1686 | ||
|
|
1f9bff6182 | ||
|
|
0f7d42ab83 | ||
|
|
60334f24f1 | ||
|
|
d7d099d2d7 | ||
|
|
514d4170be | ||
|
|
6b1c1853b8 | ||
|
|
ced318637f | ||
|
|
c2c7c37ef6 | ||
|
|
7e5041eac5 | ||
|
|
4b7db87444 | ||
|
|
22aba74ed9 | ||
|
|
5283dd2f9e | ||
|
|
8bc69ba0a4 | ||
|
|
90207c6184 | ||
|
|
678590fc4f | ||
|
|
9170aba906 | ||
|
|
59a92bb172 | ||
|
|
f12cf8a6ce | ||
|
|
26cb75f93f | ||
|
|
e8b05cd7c2 | ||
|
|
4930c07e9c | ||
|
|
39d4002491 | ||
|
|
e095b139ae | ||
|
|
088cf97ebf | ||
|
|
be90b30b8f | ||
|
|
0ff3041e89 | ||
|
|
9d2c2c0e47 | ||
|
|
b35f2b7cb4 | ||
|
|
1988c5fe9a | ||
|
|
aad99ce3a4 | ||
|
|
1d7209693a | ||
|
|
4017732d71 | ||
|
|
c09f2a1121 | ||
|
|
9467a0700a | ||
|
|
ef74faeef4 | ||
|
|
2891ad7efe | ||
|
|
364ffc4659 | ||
|
|
8aa82274ff | ||
|
|
71ca037ca8 | ||
|
|
341aac8ff7 | ||
|
|
99ccfb8e94 | ||
|
|
4ed884de55 | ||
|
|
f9caa75aa7 | ||
|
|
37a7bc43fd | ||
|
|
cdd6ac1d8b | ||
|
|
235e0efc09 | ||
|
|
2f4f93d3ba | ||
|
|
f25a1b70f3 | ||
|
|
6ec8edd5e2 | ||
|
|
8beeced7c2 | ||
|
|
f4add84a13 | ||
|
|
c507d0ed7e | ||
|
|
3ff193f42d | ||
|
|
8104050658 | ||
|
|
b53f0b4c1b | ||
|
|
7698c05dd5 | ||
|
|
18734345a1 | ||
|
|
ad54ee4bda | ||
|
|
f8a4b7b1db | ||
|
|
e6966df9ac | ||
|
|
8e17fc0edb | ||
|
|
2cdb8c022d | ||
|
|
04822346a6 | ||
|
|
6fcfc2da34 | ||
|
|
62c7b8cdc1 | ||
|
|
d2d899a8d0 | ||
|
|
921e09227f | ||
|
|
39c274a515 | ||
|
|
5db65b6e6e | ||
|
|
c71fc5575f | ||
|
|
2ebf264feb | ||
|
|
aa20cf5138 | ||
|
|
5f96a8991a | ||
|
|
47e0d6ae19 | ||
|
|
e3e2d8d2f6 | ||
|
|
f57e057f2a | ||
|
|
dc0df8cc61 | ||
|
|
c30d7a2089 | ||
|
|
03bffb3319 | ||
|
|
65dc93ed37 | ||
|
|
8ed04b9c6e | ||
|
|
e6a9327bae | ||
|
|
658c506653 | ||
|
|
ad4a4281b4 | ||
|
|
6b0070ec56 | ||
|
|
c9cf6baf4b | ||
|
|
85a25a0a39 | ||
|
|
e192d254f9 | ||
|
|
9e2b9d7cf4 | ||
|
|
cd545213e4 | ||
|
|
935d2ff02c | ||
|
|
b7d6218b89 | ||
|
|
d86754b0e6 | ||
|
|
b97674a404 | ||
|
|
f91522fc14 | ||
|
|
9b4ef00278 | ||
|
|
43270c7763 | ||
|
|
9a98fb399c | ||
|
|
c255b0249f | ||
|
|
b0e71f6f18 | ||
|
|
7e59377daf | ||
|
|
73aa369e6d | ||
|
|
731d7e5d6b | ||
|
|
bc5e1c7df9 | ||
|
|
1a15f9b581 | ||
|
|
136d6052d8 | ||
|
|
811b270bae | ||
|
|
7870e3cfce | ||
|
|
4874af1d5a | ||
|
|
1b7ead0479 | ||
|
|
ac97984314 | ||
|
|
8c778e8afb | ||
|
|
2b6bbce1d9 | ||
|
|
b8e0a9c1dd | ||
|
|
4c3c3de065 | ||
|
|
a74801a0af | ||
|
|
cbe8217790 | ||
|
|
e1cdf34955 | ||
|
|
fefc20c52a | ||
|
|
ad1e574cfe | ||
|
|
c25d4b7dad | ||
|
|
207aa88daf | ||
|
|
3be08a3e63 | ||
|
|
7d91ffbafa | ||
|
|
128ba084ad | ||
|
|
0defff8f7c | ||
|
|
6e3497e4c4 | ||
|
|
1c309b2c89 | ||
|
|
35507e7fbb | ||
|
|
bc439829cf | ||
|
|
93f433f388 | ||
|
|
f9e99e2a33 | ||
|
|
94dcf7c3f3 | ||
|
|
c3bb29182e | ||
|
|
b11f6d5b3b | ||
|
|
d2b900f7c3 | ||
|
|
bf2b5d8882 | ||
|
|
e7878bdb8f | ||
|
|
0670550521 | ||
|
|
f5df923c51 | ||
|
|
f1f62816b5 | ||
|
|
db462690b3 | ||
|
|
c28685c700 | ||
|
|
1f1780597c | ||
|
|
1590251dad | ||
|
|
d25c17342b | ||
|
|
e105022185 | ||
|
|
16931917b7 | ||
|
|
e2e316a079 | ||
|
|
1dd2151a20 | ||
|
|
c7367ad46a | ||
|
|
21045411e7 | ||
|
|
128e8834e8 | ||
|
|
7433772606 | ||
|
|
8967f5f090 | ||
|
|
3b51a6e2a9 | ||
|
|
c5cb635b4e | ||
|
|
1e9f8d707e | ||
|
|
69a0aa4bd8 | ||
|
|
581fa88055 | ||
|
|
f991ae5aed | ||
|
|
44825ece04 | ||
|
|
eac2c5c020 | ||
|
|
a593e97227 | ||
|
|
ecad786f50 | ||
|
|
9012d33c05 | ||
|
|
268751815f | ||
|
|
6529b170e6 | ||
|
|
5ce465cb30 | ||
|
|
48f1df2fd6 | ||
|
|
3e6ddf560a | ||
|
|
0051533ac8 | ||
|
|
e69ac7ca28 | ||
|
|
9c8abb8edf | ||
|
|
9ee434f275 | ||
|
|
4826d9fbf0 | ||
|
|
3fd7b8ed3c | ||
|
|
ebc8d483d9 | ||
|
|
9821d3595a | ||
|
|
f21be9d10c | ||
|
|
d221036cde | ||
|
|
1dbff48ebb | ||
|
|
43e56fc433 | ||
|
|
b3b562f4bb | ||
|
|
784ac996d3 | ||
|
|
fb6a95078d | ||
|
|
189e7b8bc9 | ||
|
|
55967ad27c | ||
|
|
e2c82af4d6 | ||
|
|
8712923bec | ||
|
|
416635179b | ||
|
|
c1b635e036 | ||
|
|
2860d8f1de | ||
|
|
c1fb07b4c7 | ||
|
|
5036c2231c | ||
|
|
c848666e17 | ||
|
|
55aef98a30 | ||
|
|
7cbbf799dc | ||
|
|
30a4e0297c | ||
|
|
5f68f51693 | ||
|
|
8e6aaf29e0 | ||
|
|
cde0e74a2e | ||
|
|
2a573cbab3 | ||
|
|
941275a1b9 | ||
|
|
c5884ec498 | ||
|
|
da06cf52ec | ||
|
|
07e8f489c1 | ||
|
|
baed2ac031 | ||
|
|
cdab138b2f | ||
|
|
06524edfb3 | ||
|
|
0e40550427 | ||
|
|
e08b6ade9e | ||
|
|
36bc4944f9 | ||
|
|
a0be95d634 | ||
|
|
faf8d4c4ad | ||
|
|
8af740caa8 | ||
|
|
69fa3521f9 | ||
|
|
991a96d3dc | ||
|
|
b10bf06305 | ||
|
|
7f54b30fbe | ||
|
|
ee79043536 | ||
|
|
c9e6611b92 | ||
|
|
73d128d89a | ||
|
|
5a240acd86 | ||
|
|
7dc4a5cf87 | ||
|
|
6d835297b2 | ||
|
|
b44c29e235 | ||
|
|
8da9a9cf27 | ||
|
|
a3617626f7 | ||
|
|
e44832ea9e | ||
|
|
f841e78dcf | ||
|
|
e7a8d48cca | ||
|
|
69e8d0e32f | ||
|
|
830d1a6bf9 | ||
|
|
e9b72b442a | ||
|
|
77ac7eca18 | ||
|
|
86d4198ffd | ||
|
|
37dfe31ac2 | ||
|
|
584e1c48e6 | ||
|
|
15766ceb97 | ||
|
|
6e79f28b69 | ||
|
|
e9632d206b | ||
|
|
a0f55bfcb5 | ||
|
|
3c32f1da6e | ||
|
|
7e13c1b22a | ||
|
|
2fc52e673f | ||
|
|
48001a660b | ||
|
|
5a6daf79b6 | ||
|
|
ae4fd9f7df | ||
|
|
7dfa8776fd | ||
|
|
a836796fcc | ||
|
|
fb131972d4 | ||
|
|
140ce358fa | ||
|
|
dd92f2dccb | ||
|
|
d62004eadf | ||
|
|
abc21e9692 | ||
|
|
a13b0d5d91 | ||
|
|
12f8c75c2d | ||
|
|
bdc1920166 | ||
|
|
8cb0d57ffe | ||
|
|
7344689263 | ||
|
|
f521ca1118 | ||
|
|
6712f1383e | ||
|
|
d756fd4a29 | ||
|
|
e070ef1b7f | ||
|
|
ea7786a002 | ||
|
|
3eec07fac1 | ||
|
|
46afa76af8 | ||
|
|
6cc1ba64d8 | ||
|
|
225596481f | ||
|
|
4ef3b3b332 | ||
|
|
e7ac768b5b | ||
|
|
b1e8833daa | ||
|
|
155d71dc80 | ||
|
|
94ebf17134 | ||
|
|
d6fe2edf0d | ||
|
|
867cd7e583 | ||
|
|
1a2471a32d | ||
|
|
057dd9c01d | ||
|
|
5a2c0e15e9 | ||
|
|
ae5ae24f6f | ||
|
|
7a2f3fe840 | ||
|
|
b46788c81a | ||
|
|
3c1f37e5f9 | ||
|
|
d8d4322b2e | ||
|
|
1613e9ce46 | ||
|
|
aee3c8db1b | ||
|
|
becaeedff1 | ||
|
|
c9c6651368 | ||
|
|
d77371912b | ||
|
|
93cb12be89 | ||
|
|
4ac2bd8e92 | ||
|
|
34d52c975e | ||
|
|
85194c7f4f | ||
|
|
af009e03a0 | ||
|
|
cef7379c07 | ||
|
|
f1e75d8593 | ||
|
|
c5a194e98c | ||
|
|
7858033628 | ||
|
|
f2405e02f6 | ||
|
|
452221daa5 | ||
|
|
91f551c2d8 | ||
|
|
2ca1763280 | ||
|
|
da4a8333f7 | ||
|
|
c0b08f3219 | ||
|
|
c273e9125c | ||
|
|
7244b95844 | ||
|
|
a298b6587d | ||
|
|
d87f6b74f3 | ||
|
|
1f0b145740 | ||
|
|
f6d528d36d | ||
|
|
ea6502a282 | ||
|
|
8a36a94e73 | ||
|
|
1604eaa239 | ||
|
|
fec2fb7ce6 | ||
|
|
d2e3b854aa | ||
|
|
f8e8d33c61 | ||
|
|
dd76135efd | ||
|
|
d7be7a69ab | ||
|
|
fd942b28c6 | ||
|
|
7c850b0405 | ||
|
|
e3bb95b3dd | ||
|
|
662d8bcfda | ||
|
|
3c0b2c64e1 | ||
|
|
ed7d42cf6d | ||
|
|
8852914ceb | ||
|
|
944778175a | ||
|
|
81704c08c9 | ||
|
|
810059e6da | ||
|
|
8d95bd16fd | ||
|
|
4600253d1e | ||
|
|
d695aa9f57 | ||
|
|
7867aac55f | ||
|
|
e26563c3d6 | ||
|
|
07ad262857 | ||
|
|
cb0abd51db | ||
|
|
cc69baf0dd | ||
|
|
852a8d04c9 | ||
|
|
ffdacb3850 | ||
|
|
062e8357fa | ||
|
|
07dece9cd7 | ||
|
|
d628a513d9 | ||
|
|
6012ad9b1e | ||
|
|
c3e618de36 | ||
|
|
6b9795fe96 | ||
|
|
f7da3a347d | ||
|
|
cf020d06c6 | ||
|
|
137b5ca4f9 | ||
|
|
82be9326a8 | ||
|
|
222282dced | ||
|
|
c7a2086850 | ||
|
|
168ac5065d | ||
|
|
158ea1984f | ||
|
|
f66d73e385 | ||
|
|
252ed1c6f2 | ||
|
|
69e35167bc | ||
|
|
2140075133 | ||
|
|
80469ead18 | ||
|
|
77dc563219 | ||
|
|
9d7f0b22f7 | ||
|
|
56b17116e3 | ||
|
|
c71791b649 | ||
|
|
c8f8fcf9d3 | ||
|
|
d41a85f4a1 | ||
|
|
3c465f9a7a | ||
|
|
c25427cf4a | ||
|
|
1c8575e40c | ||
|
|
e512eab1e8 | ||
|
|
4dd8ceb245 | ||
|
|
07e2bd4bcf | ||
|
|
05eb62bb35 | ||
|
|
0df3342757 | ||
|
|
0615f38a26 | ||
|
|
1fe63b68ee | ||
|
|
1e7dbb5331 | ||
|
|
0ddc03b7c0 | ||
|
|
becc3d0953 | ||
|
|
48b1bfaebd | ||
|
|
c043026764 | ||
|
|
0aed9fc306 | ||
|
|
739559783b | ||
|
|
0f4076acab | ||
|
|
9692ac3f4d | ||
|
|
365a333b1d | ||
|
|
f039755bde | ||
|
|
d314f1bae2 | ||
|
|
aae1915519 | ||
|
|
220df8918c | ||
|
|
3e41655902 | ||
|
|
54a23f5ae7 | ||
|
|
edffcf8902 | ||
|
|
dd55f41264 | ||
|
|
8fef0052a3 | ||
|
|
f2db10d29a | ||
|
|
33756c775c | ||
|
|
ef65dd8cc6 | ||
|
|
74d0d851ca | ||
|
|
49ebc17334 | ||
|
|
548aba5b7c | ||
|
|
dc1f1e02a1 | ||
|
|
d10b809687 | ||
|
|
ad438ef339 | ||
|
|
8a7a6ed4f5 | ||
|
|
c6097e0397 | ||
|
|
0f3e856438 | ||
|
|
5b6ec81cee | ||
|
|
e888bfbc8d | ||
|
|
b04ab65258 | ||
|
|
46b707f246 | ||
|
|
f2a6073829 | ||
|
|
e5926a5371 | ||
|
|
86c4581a50 | ||
|
|
a80074dc21 | ||
|
|
3effdd1408 | ||
|
|
b927c55216 | ||
|
|
49c590a9b5 | ||
|
|
8df6a2dd83 | ||
|
|
fe66c95a29 | ||
|
|
c080959f64 | ||
|
|
f27a88787d | ||
|
|
5853495125 | ||
|
|
f49d94948d | ||
|
|
82dad0fad3 | ||
|
|
fea99498af | ||
|
|
5582ee8ed8 | ||
|
|
f4b6db9404 | ||
|
|
5c92362aae | ||
|
|
667ea9fa64 | ||
|
|
b710750035 | ||
|
|
491ff01c79 | ||
|
|
4981145dd8 | ||
|
|
e9497b03f4 | ||
|
|
d76e518db1 | ||
|
|
a2906c6aa5 | ||
|
|
e0676c66a0 | ||
|
|
0b12c5a169 | ||
|
|
39b61fe331 | ||
|
|
83e77681d9 | ||
|
|
95a69937bd | ||
|
|
c355bd7569 | ||
|
|
559a186cd9 | ||
|
|
7e81ef37d7 | ||
|
|
2e167d260d | ||
|
|
aa50d818ec | ||
|
|
b9dd0a3877 | ||
|
|
e03ef7e214 | ||
|
|
caa05d739f | ||
|
|
f580673dea | ||
|
|
297d271e63 | ||
|
|
a28e4be5a3 | ||
|
|
6b672acdc7 | ||
|
|
26f5368264 | ||
|
|
fc5b967973 | ||
|
|
3cf497fa91 | ||
|
|
f50411e9db | ||
|
|
74eca2e527 | ||
|
|
6200e78e93 | ||
|
|
904c122ee0 | ||
|
|
741afaea18 | ||
|
|
6cf86d80e2 | ||
|
|
886305ec13 | ||
|
|
ab040f5268 | ||
|
|
8404e0f670 | ||
|
|
3605ae14b5 | ||
|
|
bce372bd79 | ||
|
|
715c48b7eb | ||
|
|
eb9a3c2ad1 | ||
|
|
b261829aea | ||
|
|
595be6b7b8 | ||
|
|
9ed76ae4da | ||
|
|
2ae0ef40d4 | ||
|
|
f5f7d3c154 | ||
|
|
a9ab4dbe38 | ||
|
|
5c3c26851c | ||
|
|
2b3696aab1 | ||
|
|
35ec0c9bcf | ||
|
|
4f915d6708 | ||
|
|
f4eb8b246b | ||
|
|
1a80e52241 | ||
|
|
afa27a04fe | ||
|
|
b82c83de5e | ||
|
|
625e2305ba | ||
|
|
6b4781b7d5 | ||
|
|
7acffabdd8 | ||
|
|
e6f2aa2399 | ||
|
|
ece7e04c7c | ||
|
|
0b4d273e08 | ||
|
|
81e8d6d99c | ||
|
|
e96444671e | ||
|
|
e52785a8b4 | ||
|
|
ddccc5ff6b | ||
|
|
8bbcef585f | ||
|
|
e58041227b | ||
|
|
3678e8fb27 | ||
|
|
1146a9125b | ||
|
|
aab0c055ed | ||
|
|
685082e212 | ||
|
|
1bb8b636b9 | ||
|
|
43c51c3b82 | ||
|
|
b9ed64fba2 | ||
|
|
ceaac03adf | ||
|
|
3085a837c8 | ||
|
|
2e5e2c8430 | ||
|
|
48df5c0eb1 | ||
|
|
fcad6766c3 | ||
|
|
c91a4670de | ||
|
|
5e7c325874 | ||
|
|
6b8a1428d7 | ||
|
|
5bd81db37e | ||
|
|
9834baedfa | ||
|
|
0b4c42859d | ||
|
|
a92b45ae26 | ||
|
|
1e2096e691 | ||
|
|
3df6ffe280 | ||
|
|
d4f370c071 | ||
|
|
b894ea866a | ||
|
|
3a300a4ca3 | ||
|
|
0ad844d10e | ||
|
|
d310a45f72 | ||
|
|
57c31804b4 | ||
|
|
5fb70a9b9a | ||
|
|
d402143989 | ||
|
|
ad8d799cf6 | ||
|
|
cec705264d | ||
|
|
28a2e61361 | ||
|
|
6017215ada | ||
|
|
8f3128e4b3 | ||
|
|
109e6f590a | ||
|
|
ac86d75e10 | ||
|
|
8f0491ea57 | ||
|
|
6403e51ba7 | ||
|
|
e0522608a4 | ||
|
|
4b9a230803 | ||
|
|
fc5246efaa | ||
|
|
4eebfbb89f | ||
|
|
353d2c4744 | ||
|
|
2718e83132 | ||
|
|
7547d1179d | ||
|
|
61e89286bc | ||
|
|
53ae715816 | ||
|
|
8cb37dba36 | ||
|
|
4426f70de7 | ||
|
|
f0ca13150f | ||
|
|
780a20689c | ||
|
|
28f9ed1d8d | ||
|
|
2b5b8ad02c | ||
|
|
d5092b1765 | ||
|
|
fda62314f9 | ||
|
|
17018c137f | ||
|
|
8838c19c39 | ||
|
|
f02a99a4e2 | ||
|
|
7b26b0f23e | ||
|
|
0e9984827a | ||
|
|
033d41863a | ||
|
|
bc540044ac | ||
|
|
76a2535da3 | ||
|
|
ff48877d16 | ||
|
|
4b8efabc5f | ||
|
|
c79be090df | ||
|
|
626eab7e8f | ||
|
|
c103b7d883 | ||
|
|
cde055e29b | ||
|
|
1cb448c42e | ||
|
|
3d05444f30 | ||
|
|
7a551189d9 | ||
|
|
b885e70fed | ||
|
|
0a27c14041 | ||
|
|
eb8e33e311 | ||
|
|
2d44a60b90 | ||
|
|
135b6a5702 | ||
|
|
706c72fda8 | ||
|
|
fb7bdba388 | ||
|
|
733d08638d | ||
|
|
cb3cca8a64 | ||
|
|
a3a581794e | ||
|
|
f921e7610c | ||
|
|
8deb364025 | ||
|
|
3a9c6f56bf | ||
|
|
a612154123 | ||
|
|
bbc5e50491 | ||
|
|
6e3dd8165e | ||
|
|
a7689a8f54 | ||
|
|
731a1af1a6 | ||
|
|
f53ebd4389 | ||
|
|
a2d61cc30a | ||
|
|
baa6ddb401 | ||
|
|
4455aa6709 | ||
|
|
315a8534d5 | ||
|
|
d77bd4034d | ||
|
|
fa71797ed2 | ||
|
|
8c63552573 | ||
|
|
a18d53c637 | ||
|
|
ffe05368e8 | ||
|
|
923d84f378 | ||
|
|
e5334aae0a | ||
|
|
4675be7e2a | ||
|
|
bf3fc61ef7 | ||
|
|
ebd9fab312 | ||
|
|
d359cf33d1 | ||
|
|
14bab1e299 | ||
|
|
4c4ad144b9 | ||
|
|
1157c0b1c5 | ||
|
|
68b2c5e0c1 | ||
|
|
b97fd06f2a | ||
|
|
51f0f5bd66 | ||
|
|
66f445997d | ||
|
|
addd199407 | ||
|
|
73d4f7c1ea | ||
|
|
25fc5562db | ||
|
|
4d52bcb5b3 | ||
|
|
3d2de560b0 | ||
|
|
809e30d906 | ||
|
|
ef9e41f20d | ||
|
|
1b4849f214 | ||
|
|
26cc67cd41 | ||
|
|
e123d139e4 | ||
|
|
a8abd52afb | ||
|
|
091e99f21b | ||
|
|
7b7875e23f | ||
|
|
b6593c2a83 | ||
|
|
5ac7887360 | ||
|
|
ed7627af6f | ||
|
|
1ea9fc54b2 | ||
|
|
3819571ec0 | ||
|
|
94f131fc57 | ||
|
|
3c20314aab | ||
|
|
1506d36407 | ||
|
|
aa4b2967c7 | ||
|
|
a42881d31f | ||
|
|
6a3ff2f235 | ||
|
|
fc4e3dc362 | ||
|
|
d6c689c5bb | ||
|
|
8676e9b900 | ||
|
|
c271cad9aa | ||
|
|
8e3bf786c0 | ||
|
|
a6ba694fbd | ||
|
|
790ccc320e | ||
|
|
26e951e59b | ||
|
|
a97581f5d7 | ||
|
|
5bf280ca4d | ||
|
|
fe00baa701 | ||
|
|
d3cb1d7f42 | ||
|
|
593363732a | ||
|
|
d00f4cf715 | ||
|
|
cac31dbb21 | ||
|
|
eb1fa6ca04 | ||
|
|
0ac515ea5a | ||
|
|
190e2a4952 | ||
|
|
0857b1bab6 | ||
|
|
f3e42fdc95 | ||
|
|
d617f3308a | ||
|
|
27cec85443 | ||
|
|
63f7cab508 | ||
|
|
ce0ac1bee1 | ||
|
|
2c2584c8df | ||
|
|
14fd4d96c3 | ||
|
|
dd7a63413c | ||
|
|
6d0c2301c1 | ||
|
|
8bf8f05add | ||
|
|
bd773d54c6 | ||
|
|
f4c52b7ed3 | ||
|
|
5b1504c8f6 | ||
|
|
06187b9a1a | ||
|
|
7fb6e57829 | ||
|
|
5ec954dbb5 | ||
|
|
a6bc30cf62 | ||
|
|
df165252fa | ||
|
|
da9c94f675 | ||
|
|
031cef6357 | ||
|
|
ef5f3efd2e | ||
|
|
bc8c4e3c7b | ||
|
|
f5da4c8bc2 | ||
|
|
644741a1ab | ||
|
|
09f46e7a27 | ||
|
|
db4e1d214f | ||
|
|
79433dd45c | ||
|
|
fe72c9b829 | ||
|
|
b37d22ba47 | ||
|
|
7fb08e618f | ||
|
|
63c6f1169b | ||
|
|
0eff8fd24d | ||
|
|
818e554d35 | ||
|
|
5a18dbaf37 | ||
|
|
ddd9bb4e99 | ||
|
|
38a2aa90e0 | ||
|
|
139137770c | ||
|
|
789bf1bd00 | ||
|
|
563e762dde | ||
|
|
28da5f8f39 | ||
|
|
5c42061fd9 | ||
|
|
843224ca35 | ||
|
|
e47e76962b | ||
|
|
2f0e4e3212 | ||
|
|
fb3e1d0d25 | ||
|
|
e9b7e55570 | ||
|
|
8c206898f0 | ||
|
|
a9c9683b8b | ||
|
|
4f43ddf088 | ||
|
|
a9c8b67975 | ||
|
|
d1b7073ff9 | ||
|
|
58afcacab9 | ||
|
|
5eddfcf196 | ||
|
|
9a87764949 | ||
|
|
fc4e40fba3 | ||
|
|
e8acfc1c26 | ||
|
|
eaadc210ae | ||
|
|
8002f3164c | ||
|
|
48f92bc52b | ||
|
|
d1e833e0a1 | ||
|
|
c5f0be2b32 | ||
|
|
dbcf3bb0ea | ||
|
|
e7a79f6cdc | ||
|
|
63b043dc4b | ||
|
|
d2a576c99c | ||
|
|
fc91e7cbdd | ||
|
|
0555361a57 | ||
|
|
c923815a01 | ||
|
|
7a4d2ac027 | ||
|
|
442e1096be | ||
|
|
6eaf8852ae | ||
|
|
3612fca707 | ||
|
|
4736d403a1 | ||
|
|
a18fd3177c | ||
|
|
5930b0f8fe | ||
|
|
1c7c64db59 | ||
|
|
9bc780bcda | ||
|
|
b3f89e0464 | ||
|
|
1de4822c67 | ||
|
|
c846e4072a | ||
|
|
c4f26bd500 | ||
|
|
041c01135a | ||
|
|
aa904f26ad | ||
|
|
ff99d37eb6 | ||
|
|
e8a500dc99 | ||
|
|
9f4f247cd2 | ||
|
|
e1ac930dd6 | ||
|
|
c20ed94f46 | ||
|
|
4efe754a8d | ||
|
|
bb83f7fcb7 | ||
|
|
79fa6082b0 | ||
|
|
f2ecc88955 | ||
|
|
7253c1ec1a | ||
|
|
cf32c9fc12 | ||
|
|
3086735be1 | ||
|
|
5a54e84dd8 | ||
|
|
1ef26c0c95 | ||
|
|
887142079b | ||
|
|
b75ea00c0d | ||
|
|
319fbfa84d | ||
|
|
3874252797 | ||
|
|
5dfc45af5f | ||
|
|
1f203801db | ||
|
|
291410a2b3 | ||
|
|
dfc4937688 | ||
|
|
a0b763ab71 | ||
|
|
ad36ac5cd9 | ||
|
|
cd40d6d7e8 | ||
|
|
ec4214ebf8 | ||
|
|
a403d40b6c | ||
|
|
7dcfc97f33 | ||
|
|
5ea056a483 | ||
|
|
cd1702bb53 | ||
|
|
6ff266581a | ||
|
|
6b7d108407 | ||
|
|
473e24bcd7 | ||
|
|
1f5056bf15 | ||
|
|
61fa062794 | ||
|
|
0e48cf4505 | ||
|
|
b606f479e9 | ||
|
|
2ccbf1ec12 | ||
|
|
ac6e84bb1c | ||
|
|
11d12c1f29 | ||
|
|
c9707e7335 | ||
|
|
2c0be68a3c | ||
|
|
2add317106 | ||
|
|
60ec11982a | ||
|
|
b2284cf1b4 | ||
|
|
e87ef2774b | ||
|
|
7a9fcaefd6 | ||
|
|
2333a7a11a | ||
|
|
2a7857c499 | ||
|
|
e892dc1eb5 | ||
|
|
9c8d1f31f6 | ||
|
|
048db7a44b | ||
|
|
1d94d494b6 | ||
|
|
c6ac35addb | ||
|
|
9ec279754b | ||
|
|
bdcf28c5da | ||
|
|
edf0f8074a | ||
|
|
c83a946cbd | ||
|
|
8604babeb6 | ||
|
|
7252b74539 | ||
|
|
08fbaa039f | ||
|
|
30f9fb50eb | ||
|
|
e3578df8a0 | ||
|
|
37445b8857 | ||
|
|
99ea14fab0 | ||
|
|
1717c143b2 | ||
|
|
53223d0876 | ||
|
|
096bcb4132 | ||
|
|
05cc70bdbd | ||
|
|
45653b52b5 | ||
|
|
d1841f2863 | ||
|
|
f85de11711 | ||
|
|
9d81a105ee | ||
|
|
deb6af9dea | ||
|
|
ab512b76aa | ||
|
|
bcbeee7247 | ||
|
|
bcdc94c3b9 | ||
|
|
6ebcf49758 | ||
|
|
a936ab6851 | ||
|
|
95378660dd | ||
|
|
e49bdac3e8 | ||
|
|
48380fab7e | ||
|
|
ce92529a84 | ||
|
|
8e29a555c8 | ||
|
|
a1b6ec066b | ||
|
|
fb59bf491f | ||
|
|
86aec7d2ba | ||
|
|
579f7d5609 | ||
|
|
c87b1ac363 | ||
|
|
543648112b | ||
|
|
daa3b9e978 | ||
|
|
fb8da181da | ||
|
|
6cc5a8af9e | ||
|
|
1a1956962a | ||
|
|
e422a1b403 | ||
|
|
295ece79ae | ||
|
|
08f8ee159a | ||
|
|
e2d416b3fb | ||
|
|
16ed97b4cb | ||
|
|
82739702bd | ||
|
|
0010c9e3d5 | ||
|
|
f59d4af92b | ||
|
|
a7df619a05 | ||
|
|
f3759c2ef5 | ||
|
|
d547f3a8a8 | ||
|
|
583e53d8a8 | ||
|
|
a27bf08ce0 | ||
|
|
060fb5ad2d | ||
|
|
ffc00d9035 | ||
|
|
83a9d281c2 | ||
|
|
b6c853c308 | ||
|
|
552c09d377 | ||
|
|
61164e627b | ||
|
|
3c71ee1ff2 | ||
|
|
07f610e84a | ||
|
|
faf344bc03 | ||
|
|
e9482a3dfc | ||
|
|
d4a7ce3487 | ||
|
|
3ef2737d82 | ||
|
|
582b67f4e1 | ||
|
|
5dd6c0af78 | ||
|
|
893e4f4723 | ||
|
|
d137e87f0e | ||
|
|
7f152077e5 | ||
|
|
74a9b229d0 | ||
|
|
80cf57a979 | ||
|
|
19ba943075 | ||
|
|
ba0e25a272 | ||
|
|
575c487fa6 | ||
|
|
1e91b2aa29 | ||
|
|
e10cf40f38 | ||
|
|
23defd2117 | ||
|
|
1227b87565 | ||
|
|
424ef16831 | ||
|
|
87059df28a | ||
|
|
520ff24ac2 | ||
|
|
920304773b | ||
|
|
e55059c82c | ||
|
|
6a96c91fe1 | ||
|
|
f995e1cf72 | ||
|
|
3be09553cf | ||
|
|
ee28a03a6c | ||
|
|
d56700a9d5 | ||
|
|
250df8b651 | ||
|
|
e071ffe590 | ||
|
|
737b45a18c | ||
|
|
1d2b7b17e8 | ||
|
|
bd71a4b581 | ||
|
|
451ff64b6f | ||
|
|
5e0dd60adb | ||
|
|
a05cd380fb | ||
|
|
fd3102c0d3 | ||
|
|
1bdd52232c | ||
|
|
381f68aaae | ||
|
|
058fde19ce | ||
|
|
63544c603d | ||
|
|
92cd8f945e | ||
|
|
5244941d9b | ||
|
|
877fb09fa3 | ||
|
|
34827ab068 | ||
|
|
9bbe875690 | ||
|
|
c7f09fb12d | ||
|
|
3f6d2bb6e3 | ||
|
|
bd2500314f | ||
|
|
a28f46a9eb | ||
|
|
7b7bd763c9 | ||
|
|
1118e4bfe0 | ||
|
|
b0bc88e9c2 | ||
|
|
038fea3539 | ||
|
|
ee20718c51 | ||
|
|
f46ffc004a | ||
|
|
d2f0f42c2d | ||
|
|
be36662efc | ||
|
|
c7d6d37a8e | ||
|
|
7ba87fcee8 | ||
|
|
c3713c9ce7 | ||
|
|
98861cea6c | ||
|
|
d89290f9b2 | ||
|
|
1b6b2ecd4d | ||
|
|
0e3575c1ca | ||
|
|
055f5c4c4e | ||
|
|
129d5445c3 | ||
|
|
6e202def1e | ||
|
|
0c51b16353 | ||
|
|
c5ee77e969 | ||
|
|
c7962abfbb | ||
|
|
d371f6ae8e | ||
|
|
8336f6a595 | ||
|
|
c3a24a6d7f | ||
|
|
f643e80de7 | ||
|
|
5473c0b38b | ||
|
|
eb54b67caa | ||
|
|
97e7e5f4a1 | ||
|
|
da64172848 | ||
|
|
e2d2e6ddd8 | ||
|
|
896cae2d07 | ||
|
|
409870dddb | ||
|
|
c19acda62d | ||
|
|
a50a6e129c | ||
|
|
d68987be0f | ||
|
|
bb64579fa5 | ||
|
|
2392d844d9 | ||
|
|
c6d01c1420 | ||
|
|
8389010002 | ||
|
|
31eb13e16d | ||
|
|
7cafbc032b | ||
|
|
cc752050f8 | ||
|
|
c90bec36c5 | ||
|
|
c1415b021a | ||
|
|
1081b4a54d | ||
|
|
ebb5fd16bb | ||
|
|
2d4a6d1fe6 | ||
|
|
11df7c28b4 | ||
|
|
17d2a63132 | ||
|
|
268486b652 | ||
|
|
f5af24b384 | ||
|
|
6d522876ad | ||
|
|
2814763b97 | ||
|
|
765133a3bd | ||
|
|
ab41a0c5d8 | ||
|
|
eee9f49c05 | ||
|
|
d7102809fc | ||
|
|
e792c119ea | ||
|
|
6e4ced8dcb | ||
|
|
e69be79aed | ||
|
|
87dc282fb7 | ||
|
|
38f7fb7c16 | ||
|
|
6173e8279f | ||
|
|
4f661c5c05 | ||
|
|
28172430dc | ||
|
|
5a9d4dd55e | ||
|
|
b3880ad380 | ||
|
|
b45c846a85 | ||
|
|
788fa693fd | ||
|
|
1d45ab1d20 | ||
|
|
ae1c3d85ab | ||
|
|
c22df2eb2a | ||
|
|
d3a130d9ba | ||
|
|
8a57b52fcc | ||
|
|
dbc9803f9e | ||
|
|
3e376eb166 | ||
|
|
12aca05aef | ||
|
|
ce1de27618 | ||
|
|
66d5148e3a | ||
|
|
d2b4a825eb | ||
|
|
f443720319 | ||
|
|
b4627a1613 | ||
|
|
ceea9c10d5 | ||
|
|
a143360497 | ||
|
|
163757cb69 | ||
|
|
4537b986ca | ||
|
|
aafac2a7a8 | ||
|
|
7344258b2f | ||
|
|
c59994b7e5 | ||
|
|
b089f59e2a | ||
|
|
649d2b7ef7 | ||
|
|
8bef575e8b | ||
|
|
559a036e6d | ||
|
|
0b845591f9 | ||
|
|
a8ef68ed59 | ||
|
|
7293b8b9dd | ||
|
|
8eef5465c9 | ||
|
|
c08cb95dc1 | ||
|
|
010166e7b0 | ||
|
|
4c7fb94616 | ||
|
|
46f486a367 | ||
|
|
ea195dcf11 | ||
|
|
e6979acded | ||
|
|
43b4fc81b9 | ||
|
|
d4ce6ebee6 | ||
|
|
1c9a5ece83 | ||
|
|
8a75664264 | ||
|
|
6687bdd258 | ||
|
|
e525ecad36 | ||
|
|
e8b5dc0649 | ||
|
|
3a0f96c1ec | ||
|
|
e4c06ba1bb | ||
|
|
bc4eadfd08 | ||
|
|
ee2ce3802f | ||
|
|
43d44634f7 | ||
|
|
41bd7fc958 | ||
|
|
1e458a642c | ||
|
|
b255e41091 | ||
|
|
bc22832ad6 | ||
|
|
f59ac505b7 | ||
|
|
e15b962221 | ||
|
|
28d4d4acc4 | ||
|
|
5f800f3723 | ||
|
|
2537ca03c8 | ||
|
|
1860402452 | ||
|
|
bec9385c68 | ||
|
|
798139e097 | ||
|
|
6683d76222 | ||
|
|
6d2d16b644 | ||
|
|
4e83cdf30f | ||
|
|
71891292b4 | ||
|
|
10ac384e7e | ||
|
|
6e7df60f2c | ||
|
|
112b583379 | ||
|
|
b07009f3ce | ||
|
|
74e9553d56 | ||
|
|
2c3d6ff02e | ||
|
|
8dd47b3a41 | ||
|
|
09f052a5d6 | ||
|
|
ac5e885fb3 | ||
|
|
dd9c8ac0b8 | ||
|
|
0de1b87028 | ||
|
|
e830a6eefe | ||
|
|
3c875a064e | ||
|
|
2227c97a57 | ||
|
|
ea211cb8ab | ||
|
|
6d2112fcd9 | ||
|
|
05cb1db020 | ||
|
|
cd4d8f02cb | ||
|
|
b8fe0d7c69 | ||
|
|
81c173e9c3 | ||
|
|
63c954dedc | ||
|
|
91d1ff1eb1 | ||
|
|
41efc572e0 | ||
|
|
77764248b5 | ||
|
|
ca0058c741 | ||
|
|
8bd74ec725 | ||
|
|
9a5983d6de | ||
|
|
ce38bf72b8 | ||
|
|
ecba54196f | ||
|
|
3b09bc877c | ||
|
|
92663aa171 | ||
|
|
c41d7ee067 | ||
|
|
5ab5f1b60f | ||
|
|
10f9c1b329 | ||
|
|
2d62ab969c | ||
|
|
7656113dcc | ||
|
|
56f0165d75 | ||
|
|
d79c4cbfe1 | ||
|
|
a55765c100 | ||
|
|
134617bbd1 | ||
|
|
2ccedd42e4 | ||
|
|
d6d1ab5099 | ||
|
|
b8d323ad59 | ||
|
|
737269bf5a | ||
|
|
e54389b79c | ||
|
|
2906c50642 | ||
|
|
8123e61e34 | ||
|
|
70cc66a7f4 | ||
|
|
13672a9d01 | ||
|
|
f2cd18f754 | ||
|
|
7e723f4142 | ||
|
|
adcd735127 | ||
|
|
70c28d4226 | ||
|
|
004e1aaead | ||
|
|
e7a5d341e4 | ||
|
|
f7b93478ed | ||
|
|
afc0c7af0e | ||
|
|
0ee5eebf91 | ||
|
|
d0fdbeb14f | ||
|
|
38f1288571 | ||
|
|
4093170599 | ||
|
|
27112a2b57 | ||
|
|
ef7722bb5c | ||
|
|
8019f4ea25 | ||
|
|
a612395ca3 | ||
|
|
4718bf166f | ||
|
|
f51bc1f1f4 | ||
|
|
64071a4a55 | ||
|
|
678bdf066e | ||
|
|
cb5562eca2 | ||
|
|
23386fccc2 | ||
|
|
4b1d6a8ac0 | ||
|
|
146408607a | ||
|
|
ffee2f067a | ||
|
|
935762506d | ||
|
|
885ce67174 | ||
|
|
e37b21760e | ||
|
|
25c2bb59f5 | ||
|
|
a1e4709910 | ||
|
|
0593e46e62 | ||
|
|
dca3033c06 | ||
|
|
d45554e162 | ||
|
|
8c4d3f3a18 | ||
|
|
6bb5c0d208 | ||
|
|
209caadd44 | ||
|
|
89fa11447a | ||
|
|
84416f566b | ||
|
|
65564065d9 | ||
|
|
79540c0232 | ||
|
|
5d23a285b4 | ||
|
|
1964a26fc3 | ||
|
|
e37a189bae | ||
|
|
5328995a79 | ||
|
|
6929eb3307 | ||
|
|
33f00f9da4 | ||
|
|
34380e8592 | ||
|
|
8185c93457 | ||
|
|
93b6bc9ca4 | ||
|
|
d76dfa4a9d | ||
|
|
d23267d333 | ||
|
|
e8a258094f | ||
|
|
ffb30bc292 | ||
|
|
fa798c8809 | ||
|
|
ac15bbc840 | ||
|
|
e26052013c | ||
|
|
9215be6bfc | ||
|
|
691c6d174b | ||
|
|
4bc9bf581e | ||
|
|
3686106dab | ||
|
|
62bc779dee | ||
|
|
843fa86c00 | ||
|
|
9bfc5b269a | ||
|
|
a7b6a67a92 | ||
|
|
9b795a0df7 | ||
|
|
29c40036b2 | ||
|
|
49e845137a | ||
|
|
394bfe2da4 | ||
|
|
6607bd319c | ||
|
|
54c5eb6155 | ||
|
|
49ec387cfa | ||
|
|
0ef6164b24 | ||
|
|
87a25ca19f | ||
|
|
e564b63f77 | ||
|
|
0e6ad3e25c | ||
|
|
c3442a1090 | ||
|
|
83e5c37b60 | ||
|
|
2dda3da8b1 | ||
|
|
7e6ee0806d | ||
|
|
9c0adb4ce6 | ||
|
|
b17136d23a | ||
|
|
edeec9568e | ||
|
|
e5ed27180f | ||
|
|
207ac11ded | ||
|
|
2bc8420c24 | ||
|
|
f4048fca04 | ||
|
|
9942d8e628 | ||
|
|
2fe282ef6a | ||
|
|
12dcd34b3d | ||
|
|
0cf4732347 | ||
|
|
4e6a402142 | ||
|
|
9449936df0 | ||
|
|
7c555465b8 | ||
|
|
5262b8ae29 | ||
|
|
1028aeea9f | ||
|
|
e02071047a | ||
|
|
227658d2fc | ||
|
|
56dc299fc9 | ||
|
|
f7e1ff14d9 | ||
|
|
9e865b3677 | ||
|
|
e4da7de06f | ||
|
|
67f45793da | ||
|
|
5a2949609e | ||
|
|
f20597656e | ||
|
|
aaf700baba | ||
|
|
a3e121d6a0 | ||
|
|
d3269e8aaa | ||
|
|
b9104df26e | ||
|
|
717f560326 | ||
|
|
6fdb93a020 | ||
|
|
767b0d8084 | ||
|
|
52eb9284f7 | ||
|
|
c355486955 | ||
|
|
0e8f87d6c6 | ||
|
|
dbd3c071e8 | ||
|
|
398995648a | ||
|
|
3fc9401d97 | ||
|
|
d31320ae4b | ||
|
|
fe54afbe1c | ||
|
|
6b5ccb4450 | ||
|
|
805baa75f4 | ||
|
|
b1dd2f0bc9 | ||
|
|
f8e926040a | ||
|
|
11690dfb8c | ||
|
|
63369223ca | ||
|
|
a1e81b58b1 | ||
|
|
cf2b6b4b39 | ||
|
|
c4e584a1da | ||
|
|
25b58b76f3 | ||
|
|
b346403887 | ||
|
|
e0cd560dfb | ||
|
|
4313e51530 | ||
|
|
e2bb90208e | ||
|
|
85d72a1c0e | ||
|
|
a073ab41dd | ||
|
|
34c24d99df | ||
|
|
69d9d9473b | ||
|
|
a58c06c617 | ||
|
|
b7a54d0512 | ||
|
|
1677582034 | ||
|
|
44b888fd04 | ||
|
|
78f9216d32 | ||
|
|
1ea0ec53af | ||
|
|
688823e63f | ||
|
|
78f4b80b84 | ||
|
|
bb8f536f0a | ||
|
|
ca51c5348e | ||
|
|
cc4d9ede97 | ||
|
|
053c2a3f1f | ||
|
|
1538e7b85b | ||
|
|
61d2a4dcb9 | ||
|
|
3c55e25432 | ||
|
|
93ad971fc0 | ||
|
|
5200de2e3e | ||
|
|
d92736b38f | ||
|
|
20f1320e2d | ||
|
|
b6af17f283 | ||
|
|
4a6a110e3d | ||
|
|
7f161a0a49 | ||
|
|
30301b51d4 | ||
|
|
c33796e97c | ||
|
|
61ee23455b | ||
|
|
1cd36b6134 | ||
|
|
59087f9198 | ||
|
|
bb231868b4 | ||
|
|
c841c0e342 | ||
|
|
4630d39663 | ||
|
|
3b529222d8 | ||
|
|
1ab2ae0df0 | ||
|
|
8c9b753544 | ||
|
|
196ce3df1b | ||
|
|
15a0bab925 | ||
|
|
95ed47934d | ||
|
|
8c2c2302d1 | ||
|
|
187a6132fc | ||
|
|
b3fd29056e | ||
|
|
11a58b5adf | ||
|
|
7c5374552d | ||
|
|
d33ff427b5 | ||
|
|
32a4607673 | ||
|
|
6f37ca8a84 | ||
|
|
f9dcd7348e | ||
|
|
f4baa67089 | ||
|
|
39f8b56c99 | ||
|
|
ea1192c334 | ||
|
|
56dfbc737d | ||
|
|
1c1a0e9b33 | ||
|
|
fcc014e5d1 | ||
|
|
bfb0576e26 | ||
|
|
71140a8c6c | ||
|
|
6d80c798f5 | ||
|
|
d3f6f2f87d | ||
|
|
d1050e9fdf | ||
|
|
105294fdaf | ||
|
|
4755f47286 | ||
|
|
77da91efa5 | ||
|
|
e679f18d93 | ||
|
|
c2531cf035 | ||
|
|
2124dfc718 | ||
|
|
ce5369a0ef | ||
|
|
ec797f8d67 | ||
|
|
ce7f30fa63 | ||
|
|
79482d3d1b | ||
|
|
93e7027f48 | ||
|
|
34580ab5ea | ||
|
|
bab0e9b710 | ||
|
|
88d4e3d9d5 | ||
|
|
47c338341d | ||
|
|
3cae0cd66f | ||
|
|
0738c25fb4 | ||
|
|
b8ebab5766 | ||
|
|
954b35032a | ||
|
|
46b9a8f663 | ||
|
|
41f87aa927 | ||
|
|
05a4ac164e | ||
|
|
44901b1e78 | ||
|
|
8ef79a6dbd | ||
|
|
940dd0f2a5 | ||
|
|
4fa7e06e19 | ||
|
|
7f2c3d531c | ||
|
|
a4621f31e3 | ||
|
|
7438b257ae | ||
|
|
cb6a0aefa4 | ||
|
|
7fba62bc49 | ||
|
|
01410a59cf | ||
|
|
e60c7a4cad | ||
|
|
8fa14bda1a | ||
|
|
469ee4c26a | ||
|
|
2627174fc0 | ||
|
|
7246dfa08e | ||
|
|
db0892d25b | ||
|
|
509416d5a0 | ||
|
|
43f444f07b | ||
|
|
bbeb99056a | ||
|
|
65aefc9fb8 | ||
|
|
27239b7513 | ||
|
|
15285ec151 | ||
|
|
d7893be541 | ||
|
|
59c07ceb96 | ||
|
|
007d876dbc | ||
|
|
3a41e59f00 | ||
|
|
3a34da9322 | ||
|
|
b3ee400b1a | ||
|
|
102413c7f4 | ||
|
|
c674fa0897 | ||
|
|
bd922f5bcc | ||
|
|
1390eff646 | ||
|
|
34b508a8dd | ||
|
|
8297c85220 | ||
|
|
795c0ed30f | ||
|
|
babbddcf28 | ||
|
|
650017c8f3 | ||
|
|
2c1eaff476 | ||
|
|
c0e135993c | ||
|
|
22011ffd54 | ||
|
|
31ebccd248 | ||
|
|
af11408ee9 | ||
|
|
99f5236959 | ||
|
|
67463d2214 | ||
|
|
3aabb83ccf | ||
|
|
82b755db84 | ||
|
|
10dc426119 | ||
|
|
233fc64c4e | ||
|
|
977ae76f9b | ||
|
|
77d9b17ac8 | ||
|
|
6f4b75ec1c | ||
|
|
2faa499ace | ||
|
|
2493d8d9f9 | ||
|
|
616c6c8bdf | ||
|
|
5421b5e926 | ||
|
|
d563ee14a9 | ||
|
|
3e5b1e74e8 | ||
|
|
f32b85a656 | ||
|
|
61e5c046c0 | ||
|
|
0eaffe213a | ||
|
|
b2a316b813 | ||
|
|
fac798df93 | ||
|
|
83a2da6b2b | ||
|
|
467ed23b37 | ||
|
|
41e0a6f0be | ||
|
|
00ebacc9db | ||
|
|
e0d44d4db1 | ||
|
|
e8a88fcbb9 | ||
|
|
d4b014188e | ||
|
|
b05207b27d | ||
|
|
c777a3d153 | ||
|
|
1bada746dc | ||
|
|
0d53afb6fd | ||
|
|
3b31d33c90 | ||
|
|
dcffb1cbaa | ||
|
|
bbd105983d | ||
|
|
1d7e0838fa | ||
|
|
d9a205d9ab | ||
|
|
39ceea9690 | ||
|
|
89891a18e5 | ||
|
|
2b59a0e6ed | ||
|
|
688aee8831 | ||
|
|
047163a38c | ||
|
|
df2a66484b | ||
|
|
69c74aa103 | ||
|
|
a4ff2a325f | ||
|
|
7109b94484 | ||
|
|
202db9eaa2 | ||
|
|
84caf2da9a | ||
|
|
9e160fec51 | ||
|
|
b7d54dfadf | ||
|
|
04e03456bf | ||
|
|
e84b16c9ce | ||
|
|
9251aff19f | ||
|
|
519baf7a3b | ||
|
|
59db2cf57c | ||
|
|
db6d3a6fa0 | ||
|
|
1209d337bc | ||
|
|
b0e54c6ff5 | ||
|
|
76f067de55 | ||
|
|
2127c53d50 | ||
|
|
bf5913fb3d | ||
|
|
9e32e4f5b2 | ||
|
|
76926f433c | ||
|
|
e03db22092 | ||
|
|
34659c4d8a | ||
|
|
caa39237ac | ||
|
|
68b219eef2 | ||
|
|
5ebf80b0cd | ||
|
|
fb2d43b022 | ||
|
|
67fa3c9ec8 | ||
|
|
041551535e | ||
|
|
5895e203ba | ||
|
|
3152e420dc | ||
|
|
fa7257fe92 | ||
|
|
077bf3430b | ||
|
|
bcfbf184c6 | ||
|
|
b9f0c259e3 | ||
|
|
6ef5642e63 | ||
|
|
29a9b1daf8 | ||
|
|
526e0f29cb | ||
|
|
d290b058eb | ||
|
|
68c7262aac | ||
|
|
68d3c1aee1 | ||
|
|
a5545147f0 | ||
|
|
32234c4d7c | ||
|
|
2c52530a92 | ||
|
|
69b1f792ba | ||
|
|
e80b174db3 | ||
|
|
90715173f7 | ||
|
|
4e1611aa07 | ||
|
|
1b4d49e80e | ||
|
|
e546214018 | ||
|
|
764259f93a | ||
|
|
cc3f824bfa | ||
|
|
3ca6bfa396 | ||
|
|
c8ac4b2d95 | ||
|
|
5f86afac0c | ||
|
|
6213f3da59 | ||
|
|
f90964bac8 | ||
|
|
e41868d405 | ||
|
|
d49bea5723 | ||
|
|
240f1fde0a | ||
|
|
86fd5f21f3 | ||
|
|
0d934c3590 | ||
|
|
e44832a419 | ||
|
|
9f954d258f | ||
|
|
710514b478 | ||
|
|
13867e2192 | ||
|
|
d7f6461415 | ||
|
|
182f204d80 | ||
|
|
a4b61927bc | ||
|
|
857274c2f3 | ||
|
|
3469e50f0a | ||
|
|
23800b17b4 | ||
|
|
f6588de023 | ||
|
|
c6d8c7189f | ||
|
|
36b57c1499 | ||
|
|
f3487d2074 | ||
|
|
35cd5c6a21 | ||
|
|
ab031cf340 | ||
|
|
0e2af5b04f | ||
|
|
44b9169cdc | ||
|
|
5763a9e756 | ||
|
|
e73ebeab93 | ||
|
|
ce6f198f08 | ||
|
|
2f6f67bdd3 | ||
|
|
a7ba118562 | ||
|
|
bb1682768a | ||
|
|
3c5c6ef8ed | ||
|
|
3d77642d3b | ||
|
|
675856d57c | ||
|
|
bb8dcf088e | ||
|
|
c829e5a40c | ||
|
|
98f9f4a225 | ||
|
|
3f568f714a | ||
|
|
2863a1f3c9 | ||
|
|
6f844f722d | ||
|
|
763d8ac423 | ||
|
|
fa652d74dc | ||
|
|
96fb3ab951 | ||
|
|
929bf7981a | ||
|
|
37eb845fe4 | ||
|
|
e9440c2326 | ||
|
|
f19958d744 | ||
|
|
66977453e1 | ||
|
|
ed596f0ba5 | ||
|
|
96d71387dc | ||
|
|
cfd94317cd | ||
|
|
ec2a65cbba | ||
|
|
6941d9e999 | ||
|
|
7eb5ffaa0d | ||
|
|
a3f5ae9e71 | ||
|
|
2fb3c2baf2 | ||
|
|
25b8d59570 | ||
|
|
1e67720c2a | ||
|
|
531c053db4 | ||
|
|
d591e24a46 | ||
|
|
1acf409b58 | ||
|
|
676b69cf1b | ||
|
|
e3563190d3 | ||
|
|
6e002a8451 | ||
|
|
cb62706791 | ||
|
|
93e3242aba |
50
.github/workflows/jekyll-gh-pages.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
|
||||
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["master"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
- name: Build with Jekyll
|
||||
uses: actions/jekyll-build-pages@v1
|
||||
with:
|
||||
source: ./docs
|
||||
destination: ./_site
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
18
.gitignore
vendored
@@ -14,3 +14,21 @@ libTINYXML2.a
|
||||
libvmix-resources.a
|
||||
rules.ninja
|
||||
/vmix
|
||||
/vimix_*.snap
|
||||
/CMakeLists.txt.user.*
|
||||
|
||||
rsc/shaders/paint.fs
|
||||
|
||||
osx/.DS_Store
|
||||
|
||||
.DS_Store
|
||||
|
||||
osx/runvimix
|
||||
|
||||
*.autosave
|
||||
|
||||
flatpak/.flatpak-builder
|
||||
|
||||
flatpak/repo/
|
||||
|
||||
flatpak/build/
|
||||
|
||||
9
.gitmodules
vendored
@@ -13,9 +13,12 @@
|
||||
[submodule "ext/Dirent"]
|
||||
path = ext/Dirent
|
||||
url = https://github.com/tronkko/dirent.git
|
||||
[submodule "ext/tfd"]
|
||||
path = ext/tfd
|
||||
url = https://github.com/native-toolkit/tinyfiledialogs.git
|
||||
[submodule "ext/glm"]
|
||||
path = ext/glm
|
||||
url = https://github.com/g-truc/glm.git
|
||||
[submodule "ext/link"]
|
||||
path = ext/link
|
||||
url = https://github.com/Ableton/link.git
|
||||
[submodule "ext/tfd"]
|
||||
path = ext/tfd
|
||||
url = https://git.code.sf.net/p/tinyfiledialogs/code
|
||||
@@ -1,66 +0,0 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "BoundingBoxVisitor.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Primitives.h"
|
||||
#include "Decorations.h"
|
||||
|
||||
BoundingBoxVisitor::BoundingBoxVisitor(): Visitor()
|
||||
{
|
||||
modelview_ = glm::identity<glm::mat4>();
|
||||
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::setModelview(glm::mat4 modelview)
|
||||
{
|
||||
modelview_ = modelview;
|
||||
}
|
||||
|
||||
GlmToolkit::AxisAlignedBoundingBox BoundingBoxVisitor::bbox()
|
||||
{
|
||||
return bbox_;
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::visit(Node &n)
|
||||
{
|
||||
// use the transform modified during update modelview_ *= n.transform_;
|
||||
glm::mat4 transform_local = GlmToolkit::transform(n.translation_, n.rotation_, n.scale_);
|
||||
modelview_ *= transform_local;
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::visit(Group &n)
|
||||
{
|
||||
if (!n.visible_)
|
||||
return;
|
||||
glm::mat4 mv = modelview_;
|
||||
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||
if ( (*node)->visible_ )
|
||||
(*node)->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::visit(Switch &n)
|
||||
{
|
||||
if (!n.visible_ || n.numChildren() < 1)
|
||||
return;
|
||||
glm::mat4 mv = modelview_;
|
||||
n.activeChild()->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::visit(Primitive &n)
|
||||
{
|
||||
if (!n.visible_)
|
||||
return;
|
||||
|
||||
bbox_.extend(n.bbox().transformed(modelview_));
|
||||
|
||||
// Log::Info("visitor box (%f, %f)-(%f, %f)", bbox_.min().x, bbox_.min().y, bbox_.max().x, bbox_.max().y);
|
||||
}
|
||||
|
||||
void BoundingBoxVisitor::visit(Scene &n)
|
||||
{
|
||||
n.ws()->accept(*this);
|
||||
}
|
||||
901
CMakeLists.txt
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
449
Decorations.cpp
@@ -1,449 +0,0 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include "Decorations.h"
|
||||
|
||||
#include "Visitor.h"
|
||||
#include "BoundingBoxVisitor.h"
|
||||
#include "ImageShader.h"
|
||||
#include "GlmToolkit.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
Frame::Frame(CornerType corner, BorderType border, ShadowType shadow) : Node(), side_(nullptr), top_(nullptr), shadow_(nullptr), square_(nullptr)
|
||||
{
|
||||
static Mesh *shadows[3] = {nullptr};
|
||||
if (shadows[0] == nullptr) {
|
||||
shadows[0] = new Mesh("mesh/glow.ply", "images/glow.dds");
|
||||
shadows[1] = new Mesh("mesh/shadow.ply", "images/shadow.dds");
|
||||
shadows[2] = new Mesh("mesh/shadow_perspective.ply", "images/shadow_perspective.dds");
|
||||
}
|
||||
static Mesh *frames[4] = {nullptr};
|
||||
if (frames[0] == nullptr) {
|
||||
frames[0] = new Mesh("mesh/border_round.ply");
|
||||
frames[1] = new Mesh("mesh/border_top.ply");
|
||||
frames[2] = new Mesh("mesh/border_large_round.ply");
|
||||
frames[3] = new Mesh("mesh/border_large_top.ply");
|
||||
}
|
||||
static LineSquare *sharpframethin = new LineSquare( 3 );
|
||||
static LineSquare *sharpframelarge = new LineSquare( 5 );
|
||||
|
||||
if (corner == SHARP) {
|
||||
if (border == LARGE)
|
||||
square_ = sharpframelarge;
|
||||
else
|
||||
square_ = sharpframethin;
|
||||
}
|
||||
else {
|
||||
// Round corners
|
||||
if (border == THIN) {
|
||||
side_ = frames[0];
|
||||
top_ = frames[1];
|
||||
}
|
||||
else{
|
||||
side_ = frames[2];
|
||||
top_ = frames[3];
|
||||
}
|
||||
}
|
||||
|
||||
switch (shadow) {
|
||||
default:
|
||||
case NONE:
|
||||
break;
|
||||
case GLOW:
|
||||
shadow_ = shadows[0];
|
||||
break;
|
||||
case DROP:
|
||||
shadow_ = shadows[1];
|
||||
break;
|
||||
case PERSPECTIVE:
|
||||
shadow_ = shadows[2];
|
||||
break;
|
||||
}
|
||||
|
||||
// switch (type) {
|
||||
// case SHARP_LARGE:
|
||||
// square_ = sharpframe;
|
||||
// shadow_ = shadows[0];
|
||||
// break;
|
||||
// case SHARP_THIN:
|
||||
// square_ = sharpframe;
|
||||
// break;
|
||||
// case ROUND_LARGE:
|
||||
// side_ = frames[2];
|
||||
// top_ = frames[3];
|
||||
// shadow_ = shadows[1];
|
||||
// break;
|
||||
// default:
|
||||
// case ROUND_THIN:
|
||||
// side_ = frames[0];
|
||||
// top_ = frames[1];
|
||||
// shadow_ = shadows[1];
|
||||
// break;
|
||||
// case ROUND_THIN_PERSPECTIVE:
|
||||
// side_ = frames[0];
|
||||
// top_ = frames[1];
|
||||
// shadow_ = shadows[2];
|
||||
// break;
|
||||
// }
|
||||
|
||||
color = glm::vec4( 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
Frame::~Frame()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Frame::update( float dt )
|
||||
{
|
||||
Node::update(dt);
|
||||
if(top_)
|
||||
top_->update(dt);
|
||||
if(side_)
|
||||
side_->update(dt);
|
||||
if(shadow_)
|
||||
shadow_->update(dt);
|
||||
if(square_)
|
||||
square_->update(dt);
|
||||
}
|
||||
|
||||
void Frame::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() ) {
|
||||
if(side_ && !side_->initialized())
|
||||
side_->init();
|
||||
if(top_ && !top_->initialized())
|
||||
top_->init();
|
||||
if(shadow_ && !shadow_->initialized())
|
||||
shadow_->init();
|
||||
if(square_ && !square_->initialized())
|
||||
square_->init();
|
||||
init();
|
||||
}
|
||||
|
||||
if ( visible_ ) {
|
||||
|
||||
glm::mat4 ctm = modelview * transform_;
|
||||
|
||||
// shadow (scaled)
|
||||
if(shadow_){
|
||||
shadow_->shader()->color.a = 0.98f;
|
||||
shadow_->draw( ctm, projection);
|
||||
}
|
||||
|
||||
// top (scaled)
|
||||
if(top_) {
|
||||
top_->shader()->color = color;
|
||||
top_->draw( ctm, projection);
|
||||
}
|
||||
|
||||
// top (scaled)
|
||||
if(square_) {
|
||||
square_->shader()->color = color;
|
||||
square_->draw( ctm, projection);
|
||||
}
|
||||
|
||||
if(side_) {
|
||||
|
||||
side_->shader()->color = color;
|
||||
|
||||
// get scale
|
||||
glm::vec4 scale = ctm * glm::vec4(1.f, 1.0f, 0.f, 0.f);
|
||||
|
||||
// get rotation
|
||||
glm::vec3 rot(0.f);
|
||||
glm::vec4 vec = ctm * glm::vec4(1.f, 0.f, 0.f, 0.f);
|
||||
rot.z = glm::orientedAngle( glm::vec3(1.f, 0.f, 0.f), glm::normalize(glm::vec3(vec)), glm::vec3(0.f, 0.f, 1.f) );
|
||||
|
||||
if(side_) {
|
||||
|
||||
// left side
|
||||
vec = ctm * glm::vec4(1.f, 0.f, 0.f, 1.f);
|
||||
side_->draw( GlmToolkit::transform(vec, rot, glm::vec3(scale.y, scale.y, 1.f)), projection );
|
||||
|
||||
// right side
|
||||
vec = ctm * glm::vec4(-1.f, 0.f, 0.f, 1.f);
|
||||
side_->draw( GlmToolkit::transform(vec, rot, glm::vec3(-scale.y, scale.y, 1.f)), projection );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Frame::accept(Visitor& v)
|
||||
{
|
||||
Node::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
Handles::Handles(Type type) : Node(), type_(type)
|
||||
{
|
||||
static Mesh *handle_rotation_ = new Mesh("mesh/border_handles_rotation.ply");
|
||||
static Mesh *handle_corner = new Mesh("mesh/border_handles_overlay.ply");
|
||||
|
||||
color = glm::vec4( 1.f, 1.f, 0.f, 1.f);
|
||||
if ( type_ == ROTATE ) {
|
||||
handle_ = handle_rotation_;
|
||||
}
|
||||
else {
|
||||
handle_ = handle_corner;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Handles::~Handles()
|
||||
{
|
||||
}
|
||||
|
||||
void Handles::update( float dt )
|
||||
{
|
||||
Node::update(dt);
|
||||
handle_->update(dt);
|
||||
}
|
||||
|
||||
void Handles::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() ) {
|
||||
if(handle_ && !handle_->initialized())
|
||||
handle_->init();
|
||||
init();
|
||||
}
|
||||
|
||||
if ( visible_ ) {
|
||||
|
||||
// set color
|
||||
handle_->shader()->color = color;
|
||||
|
||||
glm::mat4 ctm;
|
||||
glm::vec3 rot(0.f);
|
||||
glm::vec4 vec = modelview * glm::vec4(1.f, 0.f, 0.f, 0.f);
|
||||
rot.z = glm::orientedAngle( glm::vec3(1.f, 0.f, 0.f), glm::normalize(glm::vec3(vec)), glm::vec3(0.f, 0.f, 1.f) );
|
||||
// vec = modelview * glm::vec4(0.f, 1.f, 0.f, 1.f);
|
||||
// glm::vec3 scale( vec.x > 0.f ? 1.f : -1.f, vec.y > 0.f ? 1.f : -1.f, 1.f);
|
||||
// glm::vec3 scale(1.f, 1.f, 1.f);
|
||||
|
||||
// Log::Info(" (0,1) becomes (%f, %f)", scale.x, scale.y);
|
||||
|
||||
if ( type_ == RESIZE ) {
|
||||
|
||||
// 4 corners
|
||||
vec = modelview * glm::vec4(1.f, -1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
|
||||
vec = modelview * glm::vec4(1.f, 1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
|
||||
vec = modelview * glm::vec4(-1.f, -1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
|
||||
vec = modelview * glm::vec4(-1.f, 1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
}
|
||||
else if ( type_ == RESIZE_H ){
|
||||
// left and right
|
||||
vec = modelview * glm::vec4(1.f, 0.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
|
||||
vec = modelview * glm::vec4(-1.f, 0.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
}
|
||||
else if ( type_ == RESIZE_V ){
|
||||
// top and bottom
|
||||
vec = modelview * glm::vec4(0.f, 1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
|
||||
vec = modelview * glm::vec4(0.f, -1.f, 0.f, 1.f);
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
handle_->draw( ctm, projection );
|
||||
}
|
||||
else if ( type_ == ROTATE ){
|
||||
// one icon in top right corner
|
||||
// 1. Fixed displacement by (0.12,0.12) along the rotation..
|
||||
ctm = GlmToolkit::transform(glm::vec4(0.f), rot, glm::vec3(1.f));
|
||||
glm::vec4 pos = ctm * glm::vec4(0.12f, 0.12f, 0.f, 1.f);
|
||||
// Log::Info(" (0.12,0.12) becomes (%f, %f)", pos.x, pos.y);
|
||||
// 2. ..from the top right corner (1,1)
|
||||
vec = ( modelview * glm::vec4(1.f, 1.f, 0.f, 1.f) ) + pos;
|
||||
ctm = GlmToolkit::transform(vec, rot, glm::vec3(1.f));
|
||||
|
||||
// TODO fix problem with negative scale
|
||||
// glm::vec4 target = modelview * glm::vec4(1.2f, 1.2f, 0.f, 1.f);
|
||||
|
||||
// vec = modelview * glm::vec4(1.f, 1.f, 0.f, 1.f);
|
||||
// glm::vec4 dv = target - vec;
|
||||
|
||||
// Log::Info("dv (%f, %f)", dv.x, dv.y);
|
||||
// float m = dv.x < dv.y ? dv.x : dv.y;
|
||||
// Log::Info("min %f", m);
|
||||
|
||||
// ctm = GlmToolkit::transform( glm::vec3(target), rot, glm::vec3(1.f));
|
||||
|
||||
handle_->draw( ctm, projection );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Handles::accept(Visitor& v)
|
||||
{
|
||||
Node::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
Symbol::Symbol(Type t, glm::vec3 pos) : Node(), type_(t)
|
||||
{
|
||||
static Mesh *icons[9] = {nullptr};
|
||||
if (icons[0] == nullptr) {
|
||||
icons[POINT] = new Mesh("mesh/point.ply");
|
||||
icons[IMAGE] = new Mesh("mesh/icon_image.ply");
|
||||
icons[VIDEO] = new Mesh("mesh/icon_video.ply");
|
||||
icons[SESSION] = new Mesh("mesh/icon_vimix.ply");
|
||||
icons[CLONE] = new Mesh("mesh/icon_clone.ply");
|
||||
icons[RENDER] = new Mesh("mesh/icon_render.ply");
|
||||
icons[DOTS] = new Mesh("mesh/icon_dots.ply");
|
||||
icons[CIRCLES] = new Mesh("mesh/icon_circles.ply");
|
||||
icons[EMPTY] = new Mesh("mesh/icon_empty.ply");
|
||||
}
|
||||
|
||||
symbol_ = icons[type_];
|
||||
translation_ = pos;
|
||||
color = glm::vec4( 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
Symbol::~Symbol()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Symbol::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() ) {
|
||||
if(symbol_ && !symbol_->initialized())
|
||||
symbol_->init();
|
||||
init();
|
||||
}
|
||||
|
||||
if ( visible_ && symbol_) {
|
||||
|
||||
// set color
|
||||
symbol_->shader()->color = color;
|
||||
|
||||
glm::mat4 ctm = modelview * transform_;
|
||||
// correct for aspect ratio
|
||||
glm::vec4 vec = ctm * glm::vec4(1.f, 1.0f, 0.f, 0.f);
|
||||
ctm *= glm::scale(glm::identity<glm::mat4>(), glm::vec3( vec.y / vec.x, 1.f, 1.f));
|
||||
|
||||
symbol_->draw( ctm, projection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Symbol::accept(Visitor& v)
|
||||
{
|
||||
Node::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
Mesh *Disk::disk_ = nullptr;
|
||||
|
||||
Disk::Disk() : Node()
|
||||
{
|
||||
if (Disk::disk_ == nullptr)
|
||||
Disk::disk_ = new Mesh("mesh/disk.ply");
|
||||
|
||||
color = glm::vec4( 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
Disk::~Disk()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Disk::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() ) {
|
||||
if (!Disk::disk_->initialized())
|
||||
Disk::disk_->init();
|
||||
init();
|
||||
}
|
||||
|
||||
if ( visible_ ) {
|
||||
|
||||
// set color
|
||||
Disk::disk_->shader()->color = color;
|
||||
|
||||
glm::mat4 ctm = modelview * transform_;
|
||||
Disk::disk_->draw( ctm, projection);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Disk::accept(Visitor& v)
|
||||
{
|
||||
Node::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
//SelectionBox::SelectionBox()
|
||||
//{
|
||||
//// color = glm::vec4( 1.f, 1.f, 1.f, 1.f);
|
||||
// color = glm::vec4( 1.f, 0.f, 0.f, 1.f);
|
||||
// square_ = new LineSquare( 3 );
|
||||
|
||||
//}
|
||||
|
||||
//void SelectionBox::draw (glm::mat4 modelview, glm::mat4 projection)
|
||||
//{
|
||||
// if ( !initialized() ) {
|
||||
// square_->init();
|
||||
// init();
|
||||
// }
|
||||
|
||||
// if (visible_) {
|
||||
|
||||
// // use a visitor bounding box to calculate extend of all selected nodes
|
||||
// BoundingBoxVisitor vbox;
|
||||
|
||||
// // visit every child of the selection
|
||||
// for (NodeSet::iterator node = children_.begin();
|
||||
// node != children_.end(); node++) {
|
||||
// // reset the transform before
|
||||
// vbox.setModelview(glm::identity<glm::mat4>());
|
||||
// (*node)->accept(vbox);
|
||||
// }
|
||||
|
||||
// // get the bounding box
|
||||
// bbox_ = vbox.bbox();
|
||||
|
||||
//// Log::Info(" -------- visitor box (%f, %f)-(%f, %f)", bbox_.min().x, bbox_.min().y, bbox_.max().x, bbox_.max().y);
|
||||
|
||||
// // set color
|
||||
// square_->shader()->color = color;
|
||||
|
||||
// // compute transformation from bounding box
|
||||
//// glm::mat4 ctm = modelview * GlmToolkit::transform(glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f));
|
||||
// glm::mat4 ctm = modelview * GlmToolkit::transform(bbox_.center(), glm::vec3(0.f), bbox_.scale());
|
||||
|
||||
// // draw bbox
|
||||
//// square_->draw( modelview, projection);
|
||||
// square_->draw( ctm, projection);
|
||||
|
||||
// // DEBUG
|
||||
//// visible_=false;
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
106
Decorations.h
@@ -1,106 +0,0 @@
|
||||
#ifndef DECORATIONS_H
|
||||
#define DECORATIONS_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Primitives.h"
|
||||
#include "Mesh.h"
|
||||
|
||||
class Frame : public Node
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum { ROUND = 0, SHARP } CornerType;
|
||||
typedef enum { THIN = 0, LARGE } BorderType;
|
||||
typedef enum { NONE = 0, GLOW, DROP, PERSPECTIVE } ShadowType;
|
||||
|
||||
Frame(CornerType corner, BorderType border, ShadowType shadow);
|
||||
~Frame();
|
||||
|
||||
void update (float dt) override;
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
Mesh *border() const { return side_; }
|
||||
glm::vec4 color;
|
||||
|
||||
protected:
|
||||
Mesh *side_;
|
||||
Mesh *top_;
|
||||
Mesh *shadow_;
|
||||
LineSquare *square_;
|
||||
};
|
||||
|
||||
class Handles : public Node
|
||||
{
|
||||
public:
|
||||
typedef enum { RESIZE = 0, RESIZE_H, RESIZE_V, ROTATE } Type;
|
||||
Handles(Type type);
|
||||
~Handles();
|
||||
|
||||
void update (float dt) override;
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
Type type() const { return type_; }
|
||||
Primitive *handle() const { return handle_; }
|
||||
glm::vec4 color;
|
||||
|
||||
protected:
|
||||
Primitive *handle_;
|
||||
Type type_;
|
||||
|
||||
};
|
||||
|
||||
class Symbol : public Node
|
||||
{
|
||||
public:
|
||||
typedef enum { POINT = 0, IMAGE, VIDEO, SESSION, CLONE, RENDER, DOTS, CIRCLES, EMPTY } Type;
|
||||
Symbol(Type t = POINT, glm::vec3 pos = glm::vec3(0.f));
|
||||
~Symbol();
|
||||
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
Type type() const { return type_; }
|
||||
glm::vec4 color;
|
||||
|
||||
protected:
|
||||
Mesh *symbol_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
class Disk : public Node
|
||||
{
|
||||
public:
|
||||
Disk();
|
||||
~Disk();
|
||||
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
glm::vec4 color;
|
||||
|
||||
protected:
|
||||
static Mesh *disk_;
|
||||
};
|
||||
|
||||
//class SelectionBox : public Group
|
||||
//{
|
||||
//public:
|
||||
// SelectionBox();
|
||||
|
||||
// void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
|
||||
// glm::vec4 color;
|
||||
|
||||
//protected:
|
||||
// LineSquare *square_;
|
||||
// GlmToolkit::AxisAlignedBoundingBox bbox_;
|
||||
|
||||
//};
|
||||
|
||||
|
||||
#endif // DECORATIONS_H
|
||||
@@ -1,76 +0,0 @@
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "defines.h"
|
||||
#include "DrawVisitor.h"
|
||||
#include "Scene.h"
|
||||
|
||||
|
||||
DrawVisitor::DrawVisitor(Node *nodetodraw, glm::mat4 projection)
|
||||
{
|
||||
target_ = nodetodraw;
|
||||
modelview_ = glm::identity<glm::mat4>();
|
||||
projection_ = projection;
|
||||
done_ = false;
|
||||
num_duplicat_ = 1;
|
||||
transform_duplicat_ = glm::identity<glm::mat4>();
|
||||
}
|
||||
|
||||
|
||||
void DrawVisitor::loop(int num, glm::mat4 transform)
|
||||
{
|
||||
num_duplicat_ = CLAMP(num, 1, 10000);
|
||||
transform_duplicat_ = transform;
|
||||
}
|
||||
|
||||
void DrawVisitor::visit(Node &n)
|
||||
{
|
||||
// draw the target
|
||||
if ( n.id() == target_->id()) {
|
||||
|
||||
for (int i = 0; i < num_duplicat_; ++i) {
|
||||
// draw multiple copies if requested
|
||||
n.draw(modelview_, projection_);
|
||||
modelview_ *= transform_duplicat_;
|
||||
}
|
||||
|
||||
done_ = true;
|
||||
}
|
||||
|
||||
if (done_) return;
|
||||
|
||||
// update transform
|
||||
modelview_ *= n.transform_;
|
||||
}
|
||||
|
||||
|
||||
void DrawVisitor::visit(Group &n)
|
||||
{
|
||||
// no need to traverse deeper if this node was drawn already
|
||||
if (done_) return;
|
||||
|
||||
// traverse children
|
||||
glm::mat4 mv = modelview_;
|
||||
for (NodeSet::iterator node = n.begin(); !done_ && node != n.end(); node++) {
|
||||
if ( (*node)->visible_ )
|
||||
(*node)->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawVisitor::visit(Scene &n)
|
||||
{
|
||||
n.root()->accept(*this);
|
||||
}
|
||||
|
||||
void DrawVisitor::visit(Switch &n)
|
||||
{
|
||||
glm::mat4 mv = modelview_;
|
||||
n.activeChild()->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
|
||||
void DrawVisitor::visit(Primitive &n)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef DRAWVISITOR_H
|
||||
#define DRAWVISITOR_H
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "Visitor.h"
|
||||
|
||||
class DrawVisitor : public Visitor
|
||||
{
|
||||
glm::mat4 modelview_;
|
||||
glm::mat4 projection_;
|
||||
Node *target_;
|
||||
bool done_;
|
||||
int num_duplicat_;
|
||||
glm::mat4 transform_duplicat_;
|
||||
|
||||
public:
|
||||
DrawVisitor(Node *nodetodraw, glm::mat4 projection);
|
||||
|
||||
void loop(int num, glm::mat4 transform);
|
||||
|
||||
void visit(Scene& n) override;
|
||||
void visit(Node& n) override;
|
||||
void visit(Primitive& n) override;
|
||||
void visit(Group& n) override;
|
||||
void visit(Switch& n) override;
|
||||
};
|
||||
|
||||
#endif // DRAWVISITOR_H
|
||||
1219
FileDialog.cpp
119
FileDialog.h
@@ -1,119 +0,0 @@
|
||||
#ifndef __IMGUI_FILE_DIALOG_H_
|
||||
#define __IMGUI_FILE_DIALOG_H_
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <future>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#define MAX_FILE_DIALOG_NAME_BUFFER 1024
|
||||
|
||||
struct FileInfoStruct
|
||||
{
|
||||
char type = ' ';
|
||||
std::string filePath;
|
||||
std::string fileName;
|
||||
std::string ext;
|
||||
};
|
||||
|
||||
class FileDialog
|
||||
{
|
||||
private:
|
||||
std::vector<FileInfoStruct> m_FileList;
|
||||
std::map<std::string, ImVec4> m_FilterColor;
|
||||
std::string m_SelectedFileName;
|
||||
std::string m_SelectedExt;
|
||||
std::string m_CurrentPath;
|
||||
std::vector<std::string> m_CurrentPath_Decomposition;
|
||||
std::string m_Name;
|
||||
bool m_ShowDialog;
|
||||
bool m_ShowDrives;
|
||||
|
||||
public:
|
||||
static char FileNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER];
|
||||
static char DirectoryNameBuffer[MAX_FILE_DIALOG_NAME_BUFFER];
|
||||
static char SearchBuffer[MAX_FILE_DIALOG_NAME_BUFFER];
|
||||
static int FilterIndex;
|
||||
bool IsOk;
|
||||
bool m_AnyWindowsHovered;
|
||||
bool m_CreateDirectoryMode;
|
||||
|
||||
private:
|
||||
std::string dlg_key;
|
||||
std::string dlg_name;
|
||||
const char *dlg_filters;
|
||||
std::string dlg_path;
|
||||
std::string dlg_defaultFileName;
|
||||
std::string dlg_defaultExt;
|
||||
std::function<void(std::string, bool*)> dlg_optionsPane;
|
||||
size_t dlg_optionsPaneWidth;
|
||||
std::string searchTag;
|
||||
std::string dlg_userString;
|
||||
|
||||
public:
|
||||
static FileDialog* Instance()
|
||||
{
|
||||
static FileDialog *_instance = new FileDialog();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static void RenderCurrent();
|
||||
// Open an Open File dialog for TEXT file
|
||||
static void SetCurrentOpenText();
|
||||
// Open an Open File dialog for IMAGE file
|
||||
static void SetCurrentOpenImage();
|
||||
// Open an Open File dialog for MEDIA file
|
||||
static void SetCurrentOpenMedia();
|
||||
|
||||
protected:
|
||||
|
||||
FileDialog(); // Prevent construction
|
||||
FileDialog(const FileDialog&) {}; // Prevent construction by copying
|
||||
FileDialog& operator =(const FileDialog&) { return *this; }; // Prevent assignment
|
||||
~FileDialog(); // Prevent unwanted destruction
|
||||
|
||||
public:
|
||||
void OpenDialog(const std::string& vKey, const char* vName, const char* vFilters,
|
||||
const std::string& vPath, const std::string& vDefaultFileName,
|
||||
std::function<void(std::string, bool*)> vOptionsPane, size_t vOptionsPaneWidth = 250, const std::string& vUserString = "");
|
||||
void OpenDialog(const std::string& vKey, const char* vName, const char* vFilters,
|
||||
const std::string& vDefaultFileName,
|
||||
std::function<void(std::string, bool*)> vOptionsPane, size_t vOptionsPaneWidth = 250, const std::string& vUserString = "");
|
||||
void OpenDialog(const std::string& vKey, const char* vName, const char* vFilters,
|
||||
const std::string& vPath, const std::string& vDefaultFileName, const std::string& vUserString = "");
|
||||
void OpenDialog(const std::string& vKey, const char* vName, const char* vFilters,
|
||||
const std::string& vFilePathName, const std::string& vUserString = "");
|
||||
|
||||
void CloseDialog(const std::string& vKey);
|
||||
bool Render(const std::string& vKey, ImVec2 geometry);
|
||||
std::string GetFilepathName();
|
||||
std::string GetCurrentPath();
|
||||
std::string GetCurrentFileName();
|
||||
std::string GetCurrentFilter();
|
||||
std::string GetUserString();
|
||||
|
||||
void SetFilterColor(std::string vFilter, ImVec4 vColor);
|
||||
bool GetFilterColor(std::string vFilter, ImVec4 *vColor);
|
||||
void ClearFilterColor();
|
||||
|
||||
private:
|
||||
void SetPath(const std::string& vPath);
|
||||
void ScanDir(const std::string& vPath);
|
||||
void SetCurrentDir(const std::string& vPath);
|
||||
bool CreateDir(const std::string& vPath);
|
||||
void ComposeNewPath(std::vector<std::string>::iterator vIter);
|
||||
void GetDrives();
|
||||
};
|
||||
|
||||
|
||||
#endif // __IMGUI_FILE_DIALOG_H_
|
||||
221
FrameBuffer.cpp
@@ -1,221 +0,0 @@
|
||||
#include "FrameBuffer.h"
|
||||
#include "ImageShader.h"
|
||||
#include "Resource.h"
|
||||
#include "Settings.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
const char* FrameBuffer::aspect_ratio_name[4] = { "4:3", "3:2", "16:10", "16:9" };
|
||||
glm::vec2 FrameBuffer::aspect_ratio_size[4] = { glm::vec2(4.f,3.f), glm::vec2(3.f,2.f), glm::vec2(16.f,10.f), glm::vec2(16.f,9.f) };
|
||||
const char* FrameBuffer::resolution_name[4] = { "720p", "1080p", "1440", "4K" };
|
||||
float FrameBuffer::resolution_height[4] = { 720.f, 1080.f, 1440.f, 2160.f };
|
||||
|
||||
|
||||
glm::vec3 FrameBuffer::getResolutionFromParameters(int ar, int h)
|
||||
{
|
||||
float width = aspect_ratio_size[ar].x * resolution_height[h] / aspect_ratio_size[ar].y;
|
||||
glm::vec3 res = glm::vec3( width, resolution_height[h] , 0.f);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(glm::vec3 resolution, bool useAlpha, bool multiSampling): textureid_(0), intermediate_textureid_(0), framebufferid_(0), intermediate_framebufferid_(0), use_alpha_(useAlpha), use_multi_sampling_(multiSampling)
|
||||
{
|
||||
attrib_.viewport = glm::ivec2(resolution);
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, use_alpha_ ? 0.f : 1.f);
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(uint width, uint height, bool useAlpha, bool multiSampling): textureid_(0), intermediate_textureid_(0), framebufferid_(0), intermediate_framebufferid_(0), use_alpha_(useAlpha), use_multi_sampling_(multiSampling)
|
||||
{
|
||||
attrib_.viewport = glm::ivec2(width, height);
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, use_alpha_ ? 0.f : 1.f);
|
||||
}
|
||||
|
||||
void FrameBuffer::init()
|
||||
{
|
||||
// generate texture
|
||||
glGenTextures(1, &textureid_);
|
||||
glBindTexture(GL_TEXTURE_2D, textureid_);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, use_alpha_ ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// create a framebuffer object
|
||||
glGenFramebuffers(1, &framebufferid_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
// take settings into account: no multisampling for level 0
|
||||
use_multi_sampling_ &= Settings::application.render.multisampling > 0;
|
||||
|
||||
if (use_multi_sampling_){
|
||||
|
||||
// create a multisample texture
|
||||
glGenTextures(1, &intermediate_textureid_);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Settings::application.render.multisampling,
|
||||
use_alpha_ ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y, GL_TRUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
|
||||
// attach the multisampled texture to FBO (currently binded)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_, 0);
|
||||
|
||||
// create an intermediate FBO
|
||||
glGenFramebuffers(1, &intermediate_framebufferid_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
|
||||
// attach the 2D texture to intermediate FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
|
||||
// Log::Info("New FBO %d Multi Sampling ", framebufferid_);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// direct attach the 2D texture to FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
|
||||
// Log::Info("New FBO %d Single Sampling ", framebufferid_);
|
||||
}
|
||||
|
||||
checkFramebufferStatus();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
}
|
||||
|
||||
FrameBuffer::~FrameBuffer()
|
||||
{
|
||||
if (framebufferid_)
|
||||
glDeleteFramebuffers(1, &framebufferid_);
|
||||
}
|
||||
|
||||
|
||||
uint FrameBuffer::texture() const
|
||||
{
|
||||
if (framebufferid_ == 0)
|
||||
return Resource::getTextureBlack();
|
||||
|
||||
return textureid_;
|
||||
}
|
||||
|
||||
float FrameBuffer::aspectRatio() const
|
||||
{
|
||||
return static_cast<float>(attrib_.viewport.x) / static_cast<float>(attrib_.viewport.y);
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 FrameBuffer::resolution() const
|
||||
{
|
||||
return glm::vec3(attrib_.viewport.x, attrib_.viewport.y, 0.f);
|
||||
}
|
||||
|
||||
void FrameBuffer::begin()
|
||||
{
|
||||
if (!framebufferid_)
|
||||
init();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
Rendering::manager().pushAttrib(attrib_);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void FrameBuffer::end()
|
||||
{
|
||||
// if multisampling frame buffer
|
||||
if (use_multi_sampling_) {
|
||||
// blit the multisample FBO into unisample FBO to generate 2D texture
|
||||
// Doing this blit will automatically resolve the multisampled FBO.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
glBlitFramebuffer(0, 0, attrib_.viewport.x, attrib_.viewport.y,
|
||||
0, 0, attrib_.viewport.x, attrib_.viewport.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
FrameBuffer::release();
|
||||
|
||||
Rendering::manager().popAttrib();
|
||||
}
|
||||
|
||||
void FrameBuffer::release()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void FrameBuffer::readPixels()
|
||||
{
|
||||
if (!framebufferid_)
|
||||
return;
|
||||
|
||||
if (use_multi_sampling_)
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
else
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
if (use_alpha())
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
else
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glReadPixels(0, 0, attrib_.viewport.x, attrib_.viewport.y, (use_alpha_? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
bool FrameBuffer::blit(FrameBuffer *other)
|
||||
{
|
||||
if (!framebufferid_ || !other || !other->framebufferid_)
|
||||
return false;
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, other->framebufferid_);
|
||||
// blit to the frame buffer object
|
||||
glBlitFramebuffer(0, 0, attrib_.viewport.x, attrib_.viewport.y,
|
||||
0, 0, other->width(), other->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrameBuffer::checkFramebufferStatus()
|
||||
{
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
switch (status){
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT is returned if any of the framebuffer attachment points are framebuffer incomplete.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT is returned if the framebuffer does not have at least one image attached to it.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER is returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point(s) named by GL_DRAWBUFFERi.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER is returned if GL_READ_BUFFER is not GL_NONE and the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
Log::Warning("GL_FRAMEBUFFER_UNSUPPORTED is returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES.\nGL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is also returned if the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
Log::Warning("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS is returned if any framebuffer attachment is layered, and any populated attachment is not layered, or if all populated color attachments are not from textures of the same target.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
Log::Warning(" GL_FRAMEBUFFER_UNDEFINED is returned if target is the default framebuffer, but the default framebuffer does not exist.");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
#ifndef NDEBUG
|
||||
Log::Info("Framebuffer created %d x %d.", width(), height());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
#ifndef FRAMEBUFFER_H
|
||||
#define FRAMEBUFFER_H
|
||||
|
||||
#include "Scene.h"
|
||||
#include "RenderingManager.h"
|
||||
|
||||
class FrameBuffer {
|
||||
|
||||
public:
|
||||
// size descriptions
|
||||
static const char* aspect_ratio_name[4];
|
||||
static glm::vec2 aspect_ratio_size[4];
|
||||
static const char* resolution_name[4];
|
||||
static float resolution_height[4];
|
||||
static glm::vec3 getResolutionFromParameters(int ar, int h);
|
||||
// unbind any framebuffer object
|
||||
static void release();
|
||||
|
||||
FrameBuffer(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false);
|
||||
FrameBuffer(uint width, uint height, bool useAlpha = false, bool multiSampling = false);
|
||||
~FrameBuffer();
|
||||
|
||||
// Bind & push attribs to prepare draw
|
||||
void begin();
|
||||
// pop attrib and unbind to end draw
|
||||
void end();
|
||||
|
||||
// blit copy to another, returns true on success
|
||||
bool blit(FrameBuffer *other);
|
||||
// bind the FrameBuffer in READ and perform glReadPixels
|
||||
// return the size of the buffer
|
||||
void readPixels();
|
||||
|
||||
// clear color
|
||||
inline void setClearColor(glm::vec4 color) { attrib_.clear_color = color; }
|
||||
inline glm::vec4 clearColor() const { return attrib_.clear_color; }
|
||||
|
||||
// width & height
|
||||
inline uint width() const { return attrib_.viewport.x; }
|
||||
inline uint height() const { return attrib_.viewport.y; }
|
||||
glm::vec3 resolution() const;
|
||||
float aspectRatio() const;
|
||||
|
||||
// internal pixel format
|
||||
inline bool use_alpha() const { return use_alpha_; }
|
||||
inline bool use_multisampling() const { return use_multi_sampling_; }
|
||||
|
||||
// index for texturing
|
||||
uint texture() const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void checkFramebufferStatus();
|
||||
|
||||
RenderingAttrib attrib_;
|
||||
uint textureid_, intermediate_textureid_;
|
||||
uint framebufferid_, intermediate_framebufferid_;
|
||||
bool use_alpha_, use_multi_sampling_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // FRAMEBUFFER_H
|
||||
@@ -1,159 +0,0 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Scene.h"
|
||||
#include "GarbageVisitor.h"
|
||||
|
||||
|
||||
GarbageVisitor::GarbageVisitor(Node *nodetocollect) : Visitor()
|
||||
{
|
||||
targets_.push_front(nodetocollect);
|
||||
current_ = nullptr;
|
||||
found_ = false;
|
||||
}
|
||||
|
||||
GarbageVisitor::GarbageVisitor(Source *sourcetocollect) : Visitor()
|
||||
{
|
||||
targets_.push_front(sourcetocollect->group(View::MIXING));
|
||||
targets_.push_front(sourcetocollect->group(View::GEOMETRY));
|
||||
targets_.push_front(sourcetocollect->group(View::RENDERING));
|
||||
current_ = nullptr;
|
||||
found_ = false;
|
||||
}
|
||||
|
||||
|
||||
void GarbageVisitor::visit(Node &n)
|
||||
{
|
||||
// found the target
|
||||
// if (n.id() == target_->id())
|
||||
// if ( &n == target_ )
|
||||
if ( std::count(targets_.begin(), targets_.end(), &n) )
|
||||
{
|
||||
// end recursive
|
||||
found_ = true;
|
||||
|
||||
// take the node out of the Tree
|
||||
if (current_)
|
||||
current_->detatch(&n);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GarbageVisitor::~GarbageVisitor()
|
||||
{
|
||||
// actually delete the Node
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GarbageVisitor::visit(Group &n)
|
||||
{
|
||||
// no need to go further if the node was found (or is this group)
|
||||
if (found_)
|
||||
return;
|
||||
|
||||
// current group
|
||||
current_ = &n;
|
||||
|
||||
// loop over members of a group
|
||||
// and stop when found
|
||||
for (NodeSet::iterator node = n.begin(); !found_ && node != n.end(); node++) {
|
||||
// visit the child node
|
||||
(*node)->accept(*this);
|
||||
// un-stack recursive browsing
|
||||
current_ = &n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Scene &n)
|
||||
{
|
||||
n.root()->accept(*this);
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Switch &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Primitive &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Surface &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(ImageSurface &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(FrameBufferSurface &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(MediaSurface &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(MediaPlayer &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Shader &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(ImageShader &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(ImageProcessingShader &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(LineStrip &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(LineSquare &)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(LineCircle &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Mesh &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit(Frame &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GarbageVisitor::visit (Source& s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GarbageVisitor::visit (MediaSource& s)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef GARBAGEVISITOR_H
|
||||
#define GARBAGEVISITOR_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Source.h"
|
||||
#include "Visitor.h"
|
||||
|
||||
|
||||
class GarbageVisitor : public Visitor
|
||||
{
|
||||
Group *current_;
|
||||
std::list<Node *> targets_;
|
||||
bool found_;
|
||||
|
||||
public:
|
||||
GarbageVisitor(Source *sourcetocollect);
|
||||
GarbageVisitor(Node *nodetocollect);
|
||||
~GarbageVisitor();
|
||||
|
||||
void visit(Scene& n) override;
|
||||
void visit(Node& n) override;
|
||||
void visit(Group& n) override;
|
||||
void visit(Switch& n) override;
|
||||
void visit(Primitive& n) override;
|
||||
|
||||
void visit(Surface& n) override;
|
||||
void visit(ImageSurface& n) override;
|
||||
void visit(MediaSurface& n) override;
|
||||
void visit(FrameBufferSurface& n) override;
|
||||
void visit(LineStrip& n) override;
|
||||
void visit(LineSquare&) override;
|
||||
void visit(LineCircle& n) override;
|
||||
void visit(Mesh& n) override;
|
||||
void visit(Frame& n) override;
|
||||
|
||||
void visit(MediaPlayer& n) override;
|
||||
void visit(Shader& n) override;
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // GARBAGEVISITOR_H
|
||||
168
GlmToolkit.cpp
@@ -1,168 +0,0 @@
|
||||
// Freely inspired from https://github.com/alter-rokuz/glm-aabb.git
|
||||
|
||||
#include "GlmToolkit.h"
|
||||
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
glm::mat4 GlmToolkit::transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale)
|
||||
{
|
||||
glm::mat4 View = glm::translate(glm::identity<glm::mat4>(), translation);
|
||||
View = glm::rotate(View, rotation.x, glm::vec3(1.f, 0.f, 0.f));
|
||||
View = glm::rotate(View, rotation.y, glm::vec3(0.f, 1.f, 0.f));
|
||||
View = glm::rotate(View, rotation.z, glm::vec3(0.f, 0.f, 1.f));
|
||||
glm::mat4 Model = glm::scale(glm::identity<glm::mat4>(), scale);
|
||||
return View * Model;
|
||||
}
|
||||
|
||||
|
||||
GlmToolkit::AxisAlignedBoundingBox::AxisAlignedBoundingBox() {
|
||||
mMin = glm::vec3(1.f);
|
||||
mMax = glm::vec3(-1.f);
|
||||
}
|
||||
|
||||
void GlmToolkit::AxisAlignedBoundingBox::extend(const glm::vec3& point) // TODO why ref to point?
|
||||
{
|
||||
if (isNull()) {
|
||||
mMin = point;
|
||||
mMax = point;
|
||||
}
|
||||
// general case
|
||||
else {
|
||||
mMin = glm::min(point, mMin);
|
||||
mMax = glm::max(point, mMax);
|
||||
}
|
||||
}
|
||||
|
||||
void GlmToolkit::AxisAlignedBoundingBox::extend(std::vector<glm::vec3> points)
|
||||
{
|
||||
for (auto p = points.begin(); p != points.end(); p++)
|
||||
extend(*p);
|
||||
}
|
||||
|
||||
|
||||
void GlmToolkit::AxisAlignedBoundingBox::extend(const AxisAlignedBoundingBox& bb)
|
||||
{
|
||||
if (bb.isNull())
|
||||
return;
|
||||
|
||||
if (isNull()) {
|
||||
mMin = bb.mMin;
|
||||
mMax = bb.mMax;
|
||||
}
|
||||
// general case
|
||||
else {
|
||||
mMin = glm::min(bb.mMin, mMin);
|
||||
mMax = glm::max(bb.mMax, mMax);
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 GlmToolkit::AxisAlignedBoundingBox::center(bool ignore_z) const
|
||||
{
|
||||
glm::vec3 ret = glm::vec3(0.f);
|
||||
|
||||
if (!isNull())
|
||||
{
|
||||
glm::vec3 d = mMax - mMin;
|
||||
ret = mMin + (d * 0.5f);
|
||||
}
|
||||
|
||||
if (ignore_z)
|
||||
ret.z = 0.f;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
glm::vec3 GlmToolkit::AxisAlignedBoundingBox::scale(bool ignore_z) const
|
||||
{
|
||||
glm::vec3 ret = glm::vec3(1.f);
|
||||
|
||||
if (!isNull())
|
||||
{
|
||||
glm::vec3 d = mMax - mMin;
|
||||
ret = d * 0.5f;
|
||||
}
|
||||
|
||||
if (ignore_z)
|
||||
ret.z = 1.f;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GlmToolkit::AxisAlignedBoundingBox::intersect(const AxisAlignedBoundingBox& bb, bool ignore_z) const
|
||||
{
|
||||
if (isNull() || bb.isNull())
|
||||
return false;
|
||||
|
||||
if ( (mMax.x < bb.mMin.x) || (mMin.x > bb.mMax.x) ||
|
||||
(mMax.y < bb.mMin.y) || (mMin.y > bb.mMax.y) ||
|
||||
( !ignore_z && ((mMax.z < bb.mMin.z) || (mMin.z > bb.mMax.z)) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GlmToolkit::AxisAlignedBoundingBox::contains(const AxisAlignedBoundingBox& bb, bool ignore_z) const
|
||||
{
|
||||
if ( !intersect(bb, ignore_z))
|
||||
return false;
|
||||
|
||||
if ( (mMin.x <= bb.mMin.x) && (mMax.x >= bb.mMax.x) &&
|
||||
(mMin.y <= bb.mMin.y) && (mMax.y >= bb.mMax.y) &&
|
||||
( ignore_z || ((mMin.z <= bb.mMin.z) && (mMax.z >= bb.mMax.z)) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlmToolkit::AxisAlignedBoundingBox::contains(glm::vec3 point, bool ignore_z) const
|
||||
{
|
||||
if ( (mMax.x < point.x) || (mMin.x > point.x) ||
|
||||
(mMax.y < point.y) || (mMin.y > point.y) ||
|
||||
( !ignore_z && ((mMax.z < point.z) || (mMin.z > point.z)) ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::translated(glm::vec3 t)
|
||||
{
|
||||
GlmToolkit::AxisAlignedBoundingBox bb;
|
||||
bb = *this;
|
||||
|
||||
bb.mMin += t;
|
||||
bb.mMax += t;
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::scaled(glm::vec3 s)
|
||||
{
|
||||
GlmToolkit::AxisAlignedBoundingBox bb;
|
||||
bb = *this;
|
||||
|
||||
bb.mMin *= s;
|
||||
bb.mMax *= s;
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::transformed(glm::mat4 m)
|
||||
{
|
||||
GlmToolkit::AxisAlignedBoundingBox bb;
|
||||
glm::vec4 vec;
|
||||
vec = m * glm::vec4(mMin, 1.f);
|
||||
bb.mMin = glm::vec3(vec);
|
||||
|
||||
vec = m * glm::vec4(mMax, 1.f);
|
||||
bb.mMax = glm::vec3(vec);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
50
GlmToolkit.h
@@ -1,50 +0,0 @@
|
||||
#ifndef GLMTOOLKIT_H
|
||||
#define GLMTOOLKIT_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace GlmToolkit
|
||||
{
|
||||
|
||||
glm::mat4 transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale);
|
||||
|
||||
|
||||
class AxisAlignedBoundingBox
|
||||
{
|
||||
glm::vec3 mMin;
|
||||
glm::vec3 mMax;
|
||||
|
||||
public:
|
||||
AxisAlignedBoundingBox();
|
||||
|
||||
void operator = (const AxisAlignedBoundingBox &D ) {
|
||||
mMin = D.mMin;
|
||||
mMax = D.mMax;
|
||||
}
|
||||
|
||||
// test
|
||||
inline bool isNull() const { return mMin.x > mMax.x || mMin.y > mMax.y || mMin.z > mMax.z;}
|
||||
inline glm::vec3 min() const { return mMin; }
|
||||
inline glm::vec3 max() const { return mMax; }
|
||||
glm::vec3 center(bool ignore_z = true) const;
|
||||
glm::vec3 scale(bool ignore_z = true) const;
|
||||
bool intersect(const AxisAlignedBoundingBox& bb, bool ignore_z = true) const;
|
||||
bool contains(const AxisAlignedBoundingBox& bb, bool ignore_z = true) const;
|
||||
bool contains(glm::vec3 point, bool ignore_z = true) const;
|
||||
|
||||
// build
|
||||
void extend(const glm::vec3& point);
|
||||
void extend(std::vector<glm::vec3> points);
|
||||
void extend(const AxisAlignedBoundingBox& bb);
|
||||
|
||||
AxisAlignedBoundingBox translated(glm::vec3 t);
|
||||
AxisAlignedBoundingBox scaled(glm::vec3 s);
|
||||
AxisAlignedBoundingBox transformed(glm::mat4 m);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // GLMTOOLKIT_H
|
||||
@@ -1,94 +0,0 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
using namespace std;
|
||||
|
||||
#include "GstToolkit.h"
|
||||
|
||||
string GstToolkit::time_to_string(guint64 t)
|
||||
{
|
||||
if (t == GST_CLOCK_TIME_NONE)
|
||||
return "00:00:00.00";
|
||||
|
||||
guint ms = GST_TIME_AS_MSECONDS(t);
|
||||
guint s = ms / 1000;
|
||||
|
||||
ostringstream oss;
|
||||
if (s / 3600)
|
||||
oss << setw(2) << setfill('0') << s / 3600 << ':';
|
||||
if ((s % 3600) / 60)
|
||||
oss << setw(2) << setfill('0') << (s % 3600) / 60 << ':';
|
||||
oss << setw(2) << setfill('0') << (s % 3600) % 60 << '.';
|
||||
oss << setw(2) << setfill('0') << (ms % 1000) / 10;
|
||||
|
||||
// fixed length string (11 chars) HH:mm:ss.ii"
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
list<string> GstToolkit::all_plugins()
|
||||
{
|
||||
list<string> pluginlist;
|
||||
GList *l, *g;
|
||||
|
||||
l = gst_registry_get_plugin_list (gst_registry_get ());
|
||||
|
||||
for (g = l; g; g = g->next) {
|
||||
GstPlugin *plugin = GST_PLUGIN (g->data);
|
||||
pluginlist.push_front( string( gst_plugin_get_name (plugin) ) );
|
||||
}
|
||||
|
||||
gst_plugin_list_free (l);
|
||||
|
||||
return pluginlist;
|
||||
}
|
||||
|
||||
|
||||
list<string> GstToolkit::all_plugin_features(string pluginname)
|
||||
{
|
||||
list<string> featurelist;
|
||||
GList *l, *g;
|
||||
|
||||
l = gst_registry_get_feature_list_by_plugin (gst_registry_get (), pluginname.c_str());
|
||||
|
||||
for (g = l; g; g = g->next) {
|
||||
GstPluginFeature *feature = GST_PLUGIN_FEATURE (g->data);
|
||||
featurelist.push_front( string( gst_plugin_feature_get_name (feature) ) );
|
||||
}
|
||||
|
||||
gst_plugin_feature_list_free (l);
|
||||
|
||||
return featurelist;
|
||||
}
|
||||
|
||||
bool GstToolkit::enable_feature (string name, bool enable) {
|
||||
GstRegistry *registry = NULL;
|
||||
GstElementFactory *factory = NULL;
|
||||
|
||||
registry = gst_registry_get();
|
||||
if (!registry) return false;
|
||||
|
||||
factory = gst_element_factory_find (name.c_str());
|
||||
if (!factory) return false;
|
||||
|
||||
if (enable) {
|
||||
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), GST_RANK_PRIMARY + 1);
|
||||
}
|
||||
else {
|
||||
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), GST_RANK_NONE);
|
||||
}
|
||||
|
||||
gst_registry_add_feature (registry, GST_PLUGIN_FEATURE (factory));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string GstToolkit::gst_version()
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << GST_VERSION_MAJOR << '.' << GST_VERSION_MINOR << '.';
|
||||
oss << std::setw(2) << setfill('0') << GST_VERSION_MICRO ;
|
||||
if (GST_VERSION_NANO > 0)
|
||||
oss << ( (GST_VERSION_NANO < 2 ) ? " - (CVS)" : " - (Prerelease)");
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
22
GstToolkit.h
@@ -1,22 +0,0 @@
|
||||
#ifndef __GSTGUI_TOOLKIT_H_
|
||||
#define __GSTGUI_TOOLKIT_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace GstToolkit
|
||||
{
|
||||
|
||||
std::string time_to_string(guint64 t);
|
||||
|
||||
std::string gst_version();
|
||||
std::list<std::string> all_plugins();
|
||||
std::list<std::string> all_plugin_features(std::string pluginname);
|
||||
|
||||
bool enable_feature (std::string name, bool enable);
|
||||
|
||||
}
|
||||
|
||||
#endif // __GSTGUI_TOOLKIT_H_
|
||||
1042
ImGuiToolkit.cpp
@@ -1,63 +0,0 @@
|
||||
#ifndef __IMGUI_TOOLKIT_H_
|
||||
#define __IMGUI_TOOLKIT_H_
|
||||
|
||||
#include <glib.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "rsc/fonts/IconsFontAwesome5.h"
|
||||
|
||||
namespace ImGuiToolkit
|
||||
{
|
||||
// Icons from resource icon.dds
|
||||
void Icon(int i, int j);
|
||||
void ShowIconsWindow(bool* p_open);
|
||||
|
||||
// utility buttons
|
||||
bool ButtonIcon (int i, int j);
|
||||
bool ButtonIconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle);
|
||||
bool ButtonIconMultistate (std::vector<std::pair<int, int> > icons, int* state);
|
||||
void ButtonToggle (const char* label, bool* toggle);
|
||||
void ButtonSwitch (const char* label, bool* toggle , const char *help = nullptr);
|
||||
bool IconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltips[] = nullptr);
|
||||
void ButtonOpenUrl (const char* url, const ImVec2& size_arg = ImVec2(0,0));
|
||||
|
||||
void HelpMarker (const char* desc);
|
||||
|
||||
// utility sliders
|
||||
void Bar (float value, float in, float out, float min, float max, const char* title, bool expand);
|
||||
bool TimelineSlider (const char* label, guint64 *time, guint64 duration, guint64 step);
|
||||
bool TimelineSliderEdit (const char* label, guint64 *time, guint64 duration, guint64 step,
|
||||
std::list<std::pair<guint64, guint64> >& segments);
|
||||
|
||||
// fonts from ressources 'fonts/'
|
||||
typedef enum {
|
||||
FONT_DEFAULT =0,
|
||||
FONT_BOLD,
|
||||
FONT_ITALIC,
|
||||
FONT_MONO,
|
||||
FONT_LARGE
|
||||
} font_style;
|
||||
void SetFont (font_style type, const std::string &ttf_font_name, int pointsize, int oversample = 2);
|
||||
void PushFont (font_style type);
|
||||
|
||||
void WindowText(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
bool WindowButton(const char* window_name, ImVec2 window_pos, const char* text);
|
||||
void WindowDragFloat(const char* window_name, ImVec2 window_pos, float* v, float v_speed, float v_min, float v_max, const char* format);
|
||||
|
||||
|
||||
// color of gui items
|
||||
typedef enum {
|
||||
ACCENT_BLUE =0,
|
||||
ACCENT_ORANGE,
|
||||
ACCENT_GREY
|
||||
} accent_color;
|
||||
void SetAccentColor (accent_color color);
|
||||
struct ImVec4 GetHighlightColor ();
|
||||
|
||||
void ShowStats (bool* p_open, int* p_corner);
|
||||
|
||||
}
|
||||
|
||||
#endif // __IMGUI_TOOLKIT_H_
|
||||
356
ImGuiVisitor.cpp
@@ -1,356 +0,0 @@
|
||||
#include "ImGuiVisitor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "Scene.h"
|
||||
#include "Primitives.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "MediaPlayer.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "Settings.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "imgui.h"
|
||||
#include "ImGuiToolkit.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "SystemToolkit.h"
|
||||
|
||||
|
||||
ImGuiVisitor::ImGuiVisitor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Node &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Group &n)
|
||||
{
|
||||
// std::string id = std::to_string(n.id());
|
||||
// if (ImGui::TreeNode(id.c_str(), "Group %d", n.id()))
|
||||
// {
|
||||
// MODEL VIEW
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(1, 16)) {
|
||||
n.translation_.x = 0.f;
|
||||
n.translation_.y = 0.f;
|
||||
n.rotation_.z = 0.f;
|
||||
n.scale_.x = 1.f;
|
||||
n.scale_.y = 1.f;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Geometry");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(6, 15)) {
|
||||
n.translation_.x = 0.f;
|
||||
n.translation_.y = 0.f;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
float translation[2] = { n.translation_.x, n.translation_.y};
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if ( ImGui::SliderFloat2("Position", translation, -5.0, 5.0) )
|
||||
{
|
||||
n.translation_.x = translation[0];
|
||||
n.translation_.y = translation[1];
|
||||
}
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(18, 9))
|
||||
n.rotation_.z = 0.f;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderAngle("Angle", &(n.rotation_.z), -180.f, 180.f) ;
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(3, 15)) {
|
||||
n.scale_.x = 1.f;
|
||||
n.scale_.y = 1.f;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
float scale[2] = { n.scale_.x, n.scale_.y} ;
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if ( ImGui::SliderFloat2("Scale", scale, -MAX_SCALE, MAX_SCALE, "%.2f") )
|
||||
{
|
||||
n.scale_.x = CLAMP_SCALE(scale[0]);
|
||||
n.scale_.y = CLAMP_SCALE(scale[1]);
|
||||
}
|
||||
|
||||
// // loop over members of a group
|
||||
// for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||
// (*node)->accept(*this);
|
||||
// }
|
||||
|
||||
// ImGui::TreePop();
|
||||
// }
|
||||
|
||||
// spacing
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() / 2.f);
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Switch &n)
|
||||
{
|
||||
if (n.numChildren()>0)
|
||||
n.activeChild()->accept(*this);
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Scene &n)
|
||||
{
|
||||
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||
if (ImGui::CollapsingHeader("Scene Property Tree"))
|
||||
{
|
||||
n.root()->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Primitive &n)
|
||||
{
|
||||
ImGui::PushID(n.id());
|
||||
ImGui::Text("Primitive %d", n.id());
|
||||
|
||||
n.shader()->accept(*this);
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(FrameBufferSurface &n)
|
||||
{
|
||||
ImGui::Text("Framebuffer");
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(MediaSurface &n)
|
||||
{
|
||||
ImGui::Text("%s", n.path().c_str());
|
||||
|
||||
if (n.mediaPlayer())
|
||||
n.mediaPlayer()->accept(*this);
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(MediaPlayer &n)
|
||||
{
|
||||
ImGui::Text("Media Player");
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(Shader &n)
|
||||
{
|
||||
ImGui::PushID(n.id());
|
||||
|
||||
// if (ImGuiToolkit::ButtonIcon(10, 2)) {
|
||||
// n.blending = Shader::BLEND_OPACITY;
|
||||
// n.color = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
// }
|
||||
// ImGui::SameLine(0, 10);
|
||||
// ImGui::ColorEdit3("Color", glm::value_ptr(n.color), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel ) ;
|
||||
// ImGui::SameLine(0, 5);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
int mode = n.blending;
|
||||
if (ImGui::Combo("Blending", &mode, "Normal\0Screen\0Inverse\0Addition\0Subtract\0") )
|
||||
n.blending = Shader::BlendMode(mode);
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(ImageShader &n)
|
||||
{
|
||||
ImGui::PushID(n.id());
|
||||
|
||||
// get index of the mask used in this ImageShader
|
||||
int item_current = n.mask;
|
||||
|
||||
// if (ImGuiToolkit::ButtonIcon(10, 3)) n.mask = 0;
|
||||
// ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
// combo list of masks
|
||||
if ( ImGui::Combo("Mask", &item_current, ImageShader::mask_names, IM_ARRAYSIZE(ImageShader::mask_names) ) )
|
||||
{
|
||||
if (item_current < (int) ImageShader::mask_presets.size())
|
||||
n.mask = item_current;
|
||||
else {
|
||||
// TODO ask for custom mask
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit(ImageProcessingShader &n)
|
||||
{
|
||||
ImGui::PushID(n.id());
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(6, 2)) {
|
||||
ImageProcessingShader defaultvalues;
|
||||
n = defaultvalues;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Filters");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(6, 4)) n.gamma = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::ColorEdit3("GammaColor", glm::value_ptr(n.gamma), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel) ;
|
||||
ImGui::SameLine(0, 5);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Gamma", &n.gamma.w, 0.5f, 10.f, "%.2f", 2.f);
|
||||
|
||||
// ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
// ImGui::SliderFloat4("Levels", glm::value_ptr(n.levels), 0.0, 1.0);
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(4, 1)) {
|
||||
n.brightness = 0.f;
|
||||
n.contrast = 0.f;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
float bc[2] = { n.brightness, n.contrast};
|
||||
if ( ImGui::SliderFloat2("B & C", bc, -1.0, 1.0) )
|
||||
{
|
||||
n.brightness = bc[0];
|
||||
n.contrast = bc[1];
|
||||
}
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(2, 1)) n.saturation = 0.f;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Saturation", &n.saturation, -1.0, 1.0);
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(12, 4)) n.hueshift = 0.f;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Hue shift", &n.hueshift, 0.0, 1.0);
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(3, 1)) n.lumakey = 0.f;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Lumakey", &n.lumakey, 0.0, 1.0);
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(8, 1)) n.threshold = 0.f;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Threshold", &n.threshold, 0.0, 1.0, n.threshold < 0.001 ? "None" : "%.2f");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(18, 1)) n.nbColors = 0;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderInt("Posterize", &n.nbColors, 0, 16, n.nbColors == 0 ? "None" : "%d colors");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(1, 7)) n.filterid = 0;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::Combo("Filter", &n.filterid, ImageProcessingShader::filter_names, IM_ARRAYSIZE(ImageProcessingShader::filter_names) );
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(7, 1)) n.invert = 0;
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::Combo("Invert", &n.invert, "None\0Invert Color\0Invert Luminance\0");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(13, 4)) {
|
||||
n.chromakey = glm::vec4(0.f, 0.8f, 0.f, 1.f);
|
||||
n.chromadelta = 0.f;
|
||||
}
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::ColorEdit3("Chroma color", glm::value_ptr(n.chromakey), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel ) ;
|
||||
ImGui::SameLine(0, 5);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
ImGui::SliderFloat("Chromakey", &n.chromadelta, 0.0, 1.0, n.chromadelta < 0.001 ? "None" : "Tolerance %.2f");
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() / 2.f);
|
||||
}
|
||||
|
||||
|
||||
void ImGuiVisitor::visit (Source& s)
|
||||
{
|
||||
// blending
|
||||
s.blendingShader()->accept(*this);
|
||||
|
||||
// preview
|
||||
float preview_width = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN;
|
||||
ImVec2 imagesize ( preview_width, preview_width / s.frame()->aspectRatio());
|
||||
ImGui::Image((void*)(uintptr_t) s.frame()->texture(), imagesize);
|
||||
|
||||
ImVec2 pos = ImGui::GetCursorPos(); // remember where we were...
|
||||
|
||||
// toggle enable/disable image processing
|
||||
bool on = s.imageProcessingEnabled();
|
||||
ImGui::SetCursorPos( ImVec2(preview_width + 15, pos.y -ImGui::GetFrameHeight() ) );
|
||||
const char *tooltip[2] = {"GPU Image processing\nCurrently disabled", "GPU Image processing\nCurrently enabled"};
|
||||
if (ImGuiToolkit::IconToggle(12, 11, 14, 1, &on, tooltip))
|
||||
s.setImageProcessingEnabled(on);
|
||||
|
||||
ImGui::SetCursorPos(pos); // ...come back
|
||||
|
||||
// image processing pannel
|
||||
if (s.imageProcessingEnabled())
|
||||
s.processingShader()->accept(*this);
|
||||
|
||||
// geometry direct control
|
||||
s.groupNode(View::GEOMETRY)->accept(*this);
|
||||
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (MediaSource& s)
|
||||
{
|
||||
if ( s.mediaplayer()->duration() == GST_CLOCK_TIME_NONE) {
|
||||
ImGuiToolkit::Icon(2,9);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Image File");
|
||||
}
|
||||
else {
|
||||
ImGuiToolkit::Icon(18,13);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Video File");
|
||||
if ( ImGui::Button(IMGUI_TITLE_MEDIAPLAYER, ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) {
|
||||
UserInterface::manager().showMediaPlayer( s.mediaplayer());
|
||||
}
|
||||
}
|
||||
ImGuiToolkit::ButtonOpenUrl( SystemToolkit::path_filename(s.path()).c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) );
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (SessionSource& s)
|
||||
{
|
||||
ImGuiToolkit::Icon(4,9);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Session File");
|
||||
|
||||
if (ImGuiToolkit::ButtonIcon(3, 2)) s.session()->setFading(0.f);
|
||||
float f = s.session()->fading();
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::SliderFloat("Fading", &f, 0.0, 1.0, f < 0.001 ? "None" : "%.2f") )
|
||||
s.session()->setFading(f);
|
||||
|
||||
if ( ImGui::Button( ICON_FA_FILE_UPLOAD " Make Current", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
|
||||
Mixer::manager().set( s.detach() );
|
||||
if ( ImGui::Button( ICON_FA_FILE_EXPORT " Import", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
|
||||
Mixer::manager().merge( s.detach() );
|
||||
|
||||
ImGuiToolkit::ButtonOpenUrl( SystemToolkit::path_filename(s.path()).c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) );
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (RenderSource& s)
|
||||
{
|
||||
ImGuiToolkit::Icon(19,1);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Rendering Output");
|
||||
if ( ImGui::Button(IMGUI_TITLE_PREVIEW, ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
|
||||
Settings::application.widget.preview = true;
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (CloneSource& s)
|
||||
{
|
||||
ImGuiToolkit::Icon(9,2);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Clone of %s", s.origin()->name().c_str());
|
||||
std::string label = "Select " + s.origin()->name();
|
||||
if ( ImGui::Button(label.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
|
||||
Mixer::manager().setCurrentSource(s.origin());
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef IMGUIVISITOR_H
|
||||
#define IMGUIVISITOR_H
|
||||
|
||||
#include "Visitor.h"
|
||||
|
||||
class ImGuiVisitor: public Visitor
|
||||
{
|
||||
public:
|
||||
ImGuiVisitor();
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Scene& n) override;
|
||||
void visit(Node& n) override;
|
||||
void visit(Group& n) override;
|
||||
void visit(Switch& n) override;
|
||||
void visit(Primitive& n) override;
|
||||
void visit(MediaSurface& n) override;
|
||||
void visit(FrameBufferSurface& n) override;
|
||||
|
||||
// Elements with attributes
|
||||
void visit(MediaPlayer& n) override;
|
||||
void visit(Shader& n) override;
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (RenderSource& s) override;
|
||||
void visit (CloneSource& s) override;
|
||||
};
|
||||
|
||||
#endif // IMGUIVISITOR_H
|
||||
@@ -1,110 +0,0 @@
|
||||
#include "defines.h"
|
||||
#include "Visitor.h"
|
||||
#include "Log.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
|
||||
ShadingProgram imageProcessingShadingProgram("shaders/image.vs", "shaders/imageprocessing.fs");
|
||||
|
||||
const char* ImageProcessingShader::filter_names[12] = { "None", "Blur", "Sharpen", "Edge", "Emboss", "Denoising",
|
||||
"Erosion 3x3", "Erosion 5x5", "Erosion 7x7", "Dilation 3x3", "Dilation 5x5", "Dilation 7x7" };
|
||||
|
||||
|
||||
ImageProcessingShader::ImageProcessingShader()
|
||||
{
|
||||
program_ = &imageProcessingShadingProgram;
|
||||
reset();
|
||||
}
|
||||
|
||||
ImageProcessingShader::ImageProcessingShader(const ImageProcessingShader &S)
|
||||
{
|
||||
program_ = &imageProcessingShadingProgram;
|
||||
reset();
|
||||
brightness = S.brightness;
|
||||
contrast = S.contrast;
|
||||
saturation = S.saturation;
|
||||
hueshift = S.hueshift;
|
||||
threshold = S.threshold;
|
||||
lumakey = S.lumakey;
|
||||
nbColors = S.nbColors;
|
||||
invert = S.invert;
|
||||
filterid = S.filterid;
|
||||
gamma = S.gamma;
|
||||
levels = S.levels;
|
||||
chromakey = S.chromakey;
|
||||
chromadelta = S.chromadelta;
|
||||
}
|
||||
|
||||
void ImageProcessingShader::use()
|
||||
{
|
||||
Shader::use();
|
||||
|
||||
// program_->setUniform("iChannelResolution[0]", iChannelResolution[0].x, iChannelResolution[0].y, iChannelResolution[0].z);
|
||||
|
||||
program_->setUniform("brightness", brightness);
|
||||
program_->setUniform("contrast", contrast);
|
||||
program_->setUniform("saturation", saturation);
|
||||
program_->setUniform("hueshift", hueshift);
|
||||
|
||||
program_->setUniform("threshold", threshold);
|
||||
program_->setUniform("lumakey", lumakey);
|
||||
program_->setUniform("nbColors", nbColors);
|
||||
program_->setUniform("invert", invert);
|
||||
program_->setUniform("filterid", filterid);
|
||||
|
||||
program_->setUniform("gamma", gamma);
|
||||
program_->setUniform("levels", levels);
|
||||
program_->setUniform("chromakey", chromakey);
|
||||
program_->setUniform("chromadelta", chromadelta);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ImageProcessingShader::reset()
|
||||
{
|
||||
Shader::reset();
|
||||
|
||||
// // no texture resolution yet
|
||||
// iChannelResolution[0] = glm::vec3(1.f);
|
||||
|
||||
// default values for image processing
|
||||
brightness = 0.f;
|
||||
contrast = 0.f;
|
||||
saturation = 0.f;
|
||||
hueshift = 0.f;
|
||||
threshold = 0.f;
|
||||
lumakey = 0.f;
|
||||
nbColors = 0;
|
||||
invert = 0;
|
||||
filterid = 0;
|
||||
gamma = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
levels = glm::vec4(0.f, 1.f, 0.f, 1.f);
|
||||
chromakey = glm::vec4(0.f, 0.8f, 0.f, 0.f);
|
||||
chromadelta = 0.f;
|
||||
|
||||
}
|
||||
|
||||
void ImageProcessingShader::operator = (const ImageProcessingShader &S )
|
||||
{
|
||||
Shader::operator =(S);
|
||||
|
||||
brightness = S.brightness;
|
||||
contrast = S.contrast;
|
||||
saturation = S.saturation;
|
||||
hueshift = S.hueshift;
|
||||
threshold = S.threshold;
|
||||
lumakey = S.lumakey;
|
||||
nbColors = S.nbColors;
|
||||
invert = S.invert;
|
||||
filterid = S.filterid;
|
||||
gamma = S.gamma;
|
||||
levels = S.levels;
|
||||
chromakey = S.chromakey;
|
||||
chromadelta = S.chromadelta;
|
||||
}
|
||||
|
||||
|
||||
void ImageProcessingShader::accept(Visitor& v)
|
||||
{
|
||||
// Shader::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef IMAGEPROCESSINGSHADER_H
|
||||
#define IMAGEPROCESSINGSHADER_H
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Shader.h"
|
||||
|
||||
|
||||
class ImageProcessingShader : public Shader
|
||||
{
|
||||
public:
|
||||
|
||||
ImageProcessingShader();
|
||||
ImageProcessingShader(const ImageProcessingShader &model);
|
||||
|
||||
void use() override;
|
||||
void reset() override;
|
||||
void accept(Visitor& v) override;
|
||||
|
||||
void operator = (const ImageProcessingShader &S);
|
||||
|
||||
// // textures resolution
|
||||
// glm::vec3 iChannelResolution[1];
|
||||
|
||||
// color effects
|
||||
float brightness; // [-1 1]
|
||||
float contrast; // [-1 1]
|
||||
float saturation; // [-1 1]
|
||||
float hueshift; // [0 1]
|
||||
float threshold; // [0 1]
|
||||
float lumakey; // [0 1]
|
||||
// gamma
|
||||
glm::vec4 gamma;
|
||||
glm::vec4 levels;
|
||||
// discrete operations
|
||||
int nbColors;
|
||||
int invert;
|
||||
// chroma key
|
||||
glm::vec4 chromakey;
|
||||
float chromadelta;
|
||||
// filter identifyer
|
||||
// [0] No filter
|
||||
// [1 4] 4 x kernel operations; Blur, Sharpen, Edge, Emboss
|
||||
// [5] 1 x convolution opening (denoising)
|
||||
// [6 11] 6 x convolutions: erosion 3x3, 5x5, 7x7, dilation 3x3, 5x5, 7x7
|
||||
int filterid;
|
||||
static const char* filter_names[12];
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // IMAGEPROCESSINGSHADER_H
|
||||
@@ -1,79 +0,0 @@
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Visitor.h"
|
||||
#include "ImageShader.h"
|
||||
#include "Resource.h"
|
||||
|
||||
static ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs");
|
||||
|
||||
const char* ImageShader::mask_names[11] = { "None", "Glow", "Halo", "Circle", "Round", "Vignette", "Top", "Botton", "Left", "Right", "Custom" };
|
||||
std::vector< uint > ImageShader::mask_presets;
|
||||
|
||||
ImageShader::ImageShader(): Shader(), custom_textureindex(0)
|
||||
{
|
||||
// first initialization
|
||||
if ( mask_presets.empty() ) {
|
||||
mask_presets.push_back(Resource::getTextureWhite());
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_glow.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_halo.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_circle.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_roundcorner.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_vignette.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_linear_top.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_linear_bottom.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_linear_left.png"));
|
||||
mask_presets.push_back(Resource::getTextureImage("images/mask_linear_right.png"));
|
||||
}
|
||||
// static program shader
|
||||
program_ = &imageShadingProgram;
|
||||
// reset instance
|
||||
reset();
|
||||
}
|
||||
|
||||
void ImageShader::use()
|
||||
{
|
||||
Shader::use();
|
||||
|
||||
program_->setUniform("stipple", stipple);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
if ( mask < 10 ) {
|
||||
glBindTexture(GL_TEXTURE_2D, mask_presets[mask]);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, custom_textureindex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
}
|
||||
|
||||
void ImageShader::reset()
|
||||
{
|
||||
Shader::reset();
|
||||
|
||||
// default mask
|
||||
mask = 0;
|
||||
custom_textureindex = mask_presets[0];
|
||||
// no stippling
|
||||
stipple = 0.f;
|
||||
}
|
||||
|
||||
void ImageShader::operator = (const ImageShader &S )
|
||||
{
|
||||
Shader::operator =(S);
|
||||
|
||||
mask = S.mask;
|
||||
custom_textureindex = S.custom_textureindex;
|
||||
stipple = S.stipple;
|
||||
}
|
||||
|
||||
|
||||
void ImageShader::accept(Visitor& v) {
|
||||
Shader::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef IMAGESHADER_H
|
||||
#define IMAGESHADER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "Shader.h"
|
||||
|
||||
class ImageShader : public Shader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
ImageShader();
|
||||
// virtual ~ImageShader() {}
|
||||
|
||||
void use() override;
|
||||
void reset() override;
|
||||
void accept(Visitor& v) override;
|
||||
|
||||
void operator = (const ImageShader &S);
|
||||
|
||||
uint mask;
|
||||
uint custom_textureindex;
|
||||
float stipple;
|
||||
|
||||
static const char* mask_names[11];
|
||||
static std::vector< uint > mask_presets;
|
||||
};
|
||||
|
||||
#endif // IMAGESHADER_H
|
||||
1108
MediaPlayer.cpp
326
MediaPlayer.h
@@ -1,326 +0,0 @@
|
||||
#ifndef __GST_MEDIA_PLAYER_H_
|
||||
#define __GST_MEDIA_PLAYER_H_
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
|
||||
|
||||
// Forward declare classes referenced
|
||||
class Visitor;
|
||||
|
||||
#define MAX_PLAY_SPEED 20.0
|
||||
#define MIN_PLAY_SPEED 0.1
|
||||
#define N_VFRAME 3
|
||||
|
||||
struct TimeCounter {
|
||||
|
||||
GstClockTime last_time;
|
||||
GstClockTime tic_time;
|
||||
int nbFrames;
|
||||
gdouble fps;
|
||||
public:
|
||||
TimeCounter();
|
||||
GstClockTime dt();
|
||||
void tic();
|
||||
void reset();
|
||||
gdouble frameRate() const;
|
||||
};
|
||||
|
||||
struct MediaSegment
|
||||
{
|
||||
GstClockTime begin;
|
||||
GstClockTime end;
|
||||
|
||||
MediaSegment()
|
||||
{
|
||||
begin = GST_CLOCK_TIME_NONE;
|
||||
end = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
MediaSegment(GstClockTime b, GstClockTime e)
|
||||
{
|
||||
if ( b < e ) {
|
||||
begin = b;
|
||||
end = e;
|
||||
} else {
|
||||
begin = GST_CLOCK_TIME_NONE;
|
||||
end = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
}
|
||||
inline bool is_valid() const
|
||||
{
|
||||
return begin != GST_CLOCK_TIME_NONE && end != GST_CLOCK_TIME_NONE && begin < end;
|
||||
}
|
||||
inline bool operator < (const MediaSegment b) const
|
||||
{
|
||||
return (this->is_valid() && b.is_valid() && this->end < b.begin);
|
||||
}
|
||||
inline bool operator == (const MediaSegment b) const
|
||||
{
|
||||
return (this->begin == b.begin && this->end == b.end);
|
||||
}
|
||||
inline bool operator != (const MediaSegment b) const
|
||||
{
|
||||
return (this->begin != b.begin || this->end != b.end);
|
||||
}
|
||||
};
|
||||
|
||||
struct containsTime: public std::unary_function<MediaSegment, bool>
|
||||
{
|
||||
inline bool operator()(const MediaSegment s) const
|
||||
{
|
||||
return ( s.is_valid() && _t > s.begin && _t < s.end );
|
||||
}
|
||||
|
||||
containsTime(GstClockTime t) : _t(t) { }
|
||||
|
||||
private:
|
||||
GstClockTime _t;
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<MediaSegment> MediaSegmentSet;
|
||||
|
||||
class MediaPlayer {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor of a GStreamer Media
|
||||
*/
|
||||
MediaPlayer( std::string name = std::string() );
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~MediaPlayer();
|
||||
/**
|
||||
* Open a media using gstreamer URI
|
||||
* */
|
||||
void open( std::string path);
|
||||
/**
|
||||
* True if a media was oppenned
|
||||
* */
|
||||
bool isOpen() const;
|
||||
/**
|
||||
* True if problem occured
|
||||
* */
|
||||
bool failed() const;
|
||||
/**
|
||||
* Close the Media
|
||||
* */
|
||||
void close();
|
||||
/**
|
||||
* Update status
|
||||
* Must be called in update loop
|
||||
* */
|
||||
void update();
|
||||
void update_old();
|
||||
|
||||
void enable(bool on);
|
||||
|
||||
bool isEnabled() const;
|
||||
|
||||
/**
|
||||
* Pause / Play
|
||||
* Can play backward if play speed is negative
|
||||
* */
|
||||
void play(bool on);
|
||||
/**
|
||||
* Get Pause / Play
|
||||
* */
|
||||
bool isPlaying(bool testpipeline = false) const;
|
||||
/**
|
||||
* Speed factor for playing
|
||||
* Can be negative.
|
||||
* */
|
||||
double playSpeed() const;
|
||||
/**
|
||||
* Set the speed factor for playing
|
||||
* Can be negative.
|
||||
* */
|
||||
void setPlaySpeed(double s);
|
||||
/**
|
||||
* True if the player will loop when at begin or end
|
||||
* */
|
||||
typedef enum {
|
||||
LOOP_NONE = 0,
|
||||
LOOP_REWIND = 1,
|
||||
LOOP_BIDIRECTIONAL = 2
|
||||
} LoopMode;
|
||||
LoopMode loop() const;
|
||||
/**
|
||||
* Set the player to loop
|
||||
* */
|
||||
void setLoop(LoopMode mode);
|
||||
/**
|
||||
* Restart from zero
|
||||
* */
|
||||
void rewind();
|
||||
/**
|
||||
* Seek to next frame when paused
|
||||
* Can go backward if play speed is negative
|
||||
* */
|
||||
void seekNextFrame();
|
||||
/**
|
||||
* Seek to any position in media
|
||||
* pos in nanoseconds.
|
||||
* */
|
||||
void seekTo(GstClockTime pos);
|
||||
/**
|
||||
* Jump by 10% of the duration
|
||||
* */
|
||||
void fastForward();
|
||||
/**
|
||||
* Get position time
|
||||
* */
|
||||
GstClockTime position();
|
||||
/**
|
||||
* Get total duration time
|
||||
* */
|
||||
GstClockTime duration();
|
||||
/**
|
||||
* Get duration of one frame
|
||||
* */
|
||||
GstClockTime frameDuration();
|
||||
/**
|
||||
* Get framerate of the media
|
||||
* */
|
||||
double frameRate() const;
|
||||
/**
|
||||
* Get name of Codec of the media
|
||||
* */
|
||||
std::string codec() const;
|
||||
/**
|
||||
* Get rendering update framerate
|
||||
* measured during play
|
||||
* */
|
||||
double updateFrameRate() const;
|
||||
/**
|
||||
* Get the OpenGL texture
|
||||
* Must be called in OpenGL context
|
||||
* */
|
||||
guint texture() const;
|
||||
/**
|
||||
* Get Image properties
|
||||
* */
|
||||
guint width() const;
|
||||
guint height() const;
|
||||
float aspectRatio() const;
|
||||
|
||||
/**
|
||||
* Get name of the media
|
||||
* */
|
||||
std::string uri() const;
|
||||
std::string filename() const;
|
||||
|
||||
/**
|
||||
* Accept visitors
|
||||
* */
|
||||
void accept(Visitor& v);
|
||||
|
||||
/**
|
||||
* @brief registered
|
||||
* @return list of media players currently registered
|
||||
*/
|
||||
static std::list<MediaPlayer*> registered() { return registered_; }
|
||||
static std::list<MediaPlayer*>::const_iterator begin() { return registered_.cbegin(); }
|
||||
static std::list<MediaPlayer*>::const_iterator end() { return registered_.cend(); }
|
||||
|
||||
private:
|
||||
|
||||
bool addPlaySegment(GstClockTime begin, GstClockTime end);
|
||||
bool addPlaySegment(MediaSegment s);
|
||||
bool removePlaySegmentAt(GstClockTime t);
|
||||
bool removeAllPlaySegmentOverlap(MediaSegment s);
|
||||
std::list< std::pair<guint64, guint64> > getPlaySegments() const;
|
||||
|
||||
std::string id_;
|
||||
std::string filename_;
|
||||
std::string uri_;
|
||||
guint textureindex_;
|
||||
guint width_;
|
||||
guint height_;
|
||||
guint par_width_; // width to match pixel aspect ratio
|
||||
guint bitrate_;
|
||||
GstClockTime position_;
|
||||
GstClockTime start_position_;
|
||||
GstClockTime duration_;
|
||||
GstClockTime frame_duration_;
|
||||
gdouble rate_;
|
||||
LoopMode loop_;
|
||||
TimeCounter timecount_;
|
||||
gdouble framerate_;
|
||||
GstState desired_state_;
|
||||
GstElement *pipeline_;
|
||||
GstDiscoverer *discoverer_;
|
||||
std::stringstream discoverer_message_;
|
||||
std::string codec_name_;
|
||||
GstVideoInfo v_frame_video_info_;
|
||||
|
||||
// frame stack
|
||||
typedef enum {
|
||||
EMPTY = 0,
|
||||
SAMPLE = 1,
|
||||
PREROLL = 2,
|
||||
EOS = 4
|
||||
} FrameStatus;
|
||||
|
||||
struct Frame {
|
||||
GstVideoFrame vframe;
|
||||
FrameStatus status;
|
||||
GstClockTime position;
|
||||
std::mutex access;
|
||||
|
||||
Frame() {
|
||||
vframe.buffer = nullptr;
|
||||
status = EMPTY;
|
||||
position = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
};
|
||||
Frame frame_[N_VFRAME];
|
||||
guint write_index_;
|
||||
guint last_index_;
|
||||
std::mutex index_lock_;
|
||||
|
||||
// for PBO
|
||||
guint pbo_[2];
|
||||
guint pbo_index_, pbo_next_index_;
|
||||
guint pbo_size_;
|
||||
|
||||
MediaSegmentSet segments_;
|
||||
MediaSegmentSet::iterator current_segment_;
|
||||
|
||||
bool ready_;
|
||||
bool failed_;
|
||||
bool seekable_;
|
||||
bool isimage_;
|
||||
bool interlaced_;
|
||||
bool enabled_;
|
||||
|
||||
void execute_open();
|
||||
void execute_loop_command();
|
||||
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
|
||||
|
||||
// gst frame filling
|
||||
void init_texture(guint index);
|
||||
void fill_texture(guint index);
|
||||
bool fill_frame(GstBuffer *buf, FrameStatus status);
|
||||
static void callback_end_of_stream (GstAppSink *, gpointer);
|
||||
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
|
||||
static GstFlowReturn callback_new_sample (GstAppSink *, gpointer);
|
||||
|
||||
static void callback_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m);
|
||||
static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m);
|
||||
|
||||
static std::list<MediaPlayer*> registered_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __GST_MEDIA_PLAYER_H_
|
||||
148
MediaSource.cpp
@@ -1,148 +0,0 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "MediaSource.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "Resource.h"
|
||||
#include "Primitives.h"
|
||||
#include "MediaPlayer.h"
|
||||
#include "Visitor.h"
|
||||
#include "Log.h"
|
||||
|
||||
MediaSource::MediaSource() : Source(), path_("")
|
||||
{
|
||||
// create media player
|
||||
mediaplayer_ = new MediaPlayer;
|
||||
|
||||
// create media surface:
|
||||
// - textured with original texture from media player
|
||||
// - crop & repeat UV can be managed here
|
||||
// - additional custom shader can be associated
|
||||
mediasurface_ = new Surface(renderingshader_);
|
||||
|
||||
}
|
||||
|
||||
MediaSource::~MediaSource()
|
||||
{
|
||||
// delete media surface & player
|
||||
delete mediasurface_;
|
||||
delete mediaplayer_;
|
||||
}
|
||||
|
||||
void MediaSource::setPath(const std::string &p)
|
||||
{
|
||||
path_ = p;
|
||||
mediaplayer_->open(path_);
|
||||
mediaplayer_->play(true);
|
||||
|
||||
Log::Notify("Opening %s", p.c_str());
|
||||
}
|
||||
|
||||
std::string MediaSource::path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
MediaPlayer *MediaSource::mediaplayer() const
|
||||
{
|
||||
return mediaplayer_;
|
||||
}
|
||||
|
||||
bool MediaSource::failed() const
|
||||
{
|
||||
return mediaplayer_->failed();
|
||||
}
|
||||
|
||||
uint MediaSource::texture() const
|
||||
{
|
||||
return mediaplayer_->texture();
|
||||
}
|
||||
|
||||
void MediaSource::replaceRenderingShader()
|
||||
{
|
||||
mediasurface_->replaceShader(renderingshader_);
|
||||
}
|
||||
|
||||
void MediaSource::init()
|
||||
{
|
||||
if ( mediaplayer_->isOpen() ) {
|
||||
|
||||
// update video
|
||||
mediaplayer_->update();
|
||||
|
||||
// once the texture of media player is created
|
||||
if (mediaplayer_->texture() != Resource::getTextureBlack()) {
|
||||
|
||||
// get the texture index from media player, apply it to the media surface
|
||||
mediasurface_->setTextureIndex( mediaplayer_->texture() );
|
||||
|
||||
// create Frame buffer matching size of media player
|
||||
float height = float(mediaplayer()->width()) / mediaplayer()->aspectRatio();
|
||||
FrameBuffer *renderbuffer = new FrameBuffer(mediaplayer()->width(), (uint)height, true);
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
|
||||
// icon in mixing view
|
||||
if (mediaplayer_->duration() == GST_CLOCK_TIME_NONE) {
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
}
|
||||
else {
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::VIDEO, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::VIDEO, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
}
|
||||
|
||||
// done init
|
||||
initialized_ = true;
|
||||
Log::Info("Source Media linked to Media %s.", mediaplayer()->uri().c_str());
|
||||
|
||||
// force update of activation mode
|
||||
active_ = true;
|
||||
touch();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MediaSource::setActive (bool on)
|
||||
{
|
||||
bool was_active = active_;
|
||||
|
||||
Source::setActive(on);
|
||||
|
||||
// change status of media player (only if status changed)
|
||||
if ( active_ != was_active ) {
|
||||
mediaplayer()->enable(active_);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaSource::update(float dt)
|
||||
{
|
||||
Source::update(dt);
|
||||
|
||||
// update video
|
||||
if (active_)
|
||||
mediaplayer_->update();
|
||||
}
|
||||
|
||||
void MediaSource::render()
|
||||
{
|
||||
if (!initialized_)
|
||||
init();
|
||||
else {
|
||||
// render the media player into frame buffer
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -1.f, 1.f);
|
||||
renderbuffer_->begin();
|
||||
mediasurface_->draw(glm::identity<glm::mat4>(), projection);
|
||||
renderbuffer_->end();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
759
Mixer.cpp
@@ -1,759 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
// GStreamer
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
#include "tinyxml2Toolkit.h"
|
||||
using namespace tinyxml2;
|
||||
|
||||
#include "defines.h"
|
||||
#include "Settings.h"
|
||||
#include "Log.h"
|
||||
#include "View.h"
|
||||
#include "SystemToolkit.h"
|
||||
//#include "GarbageVisitor.h"
|
||||
#include "SessionVisitor.h"
|
||||
#include "SessionCreator.h"
|
||||
#include "SessionSource.h"
|
||||
#include "MediaSource.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
// static semaphore to prevent multiple threads for load / save
|
||||
static std::atomic<bool> sessionThreadActive_ = false;
|
||||
static std::atomic<bool> sessionSwapRequested_ = false;
|
||||
|
||||
// static multithreaded session loading
|
||||
static void loadSession(const std::string& filename, Session *session)
|
||||
{
|
||||
while (sessionThreadActive_)
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds(50));
|
||||
sessionThreadActive_ = true;
|
||||
|
||||
// actual loading of xml file
|
||||
SessionCreator creator( session );
|
||||
|
||||
if (creator.load(filename)) {
|
||||
// loaded ok
|
||||
session->setFilename(filename);
|
||||
|
||||
// internal update flag
|
||||
sessionSwapRequested_ = true;
|
||||
|
||||
// notification
|
||||
Log::Notify("Session %s loaded. %d source(s) created.", filename.c_str(), session->numSource());
|
||||
}
|
||||
else {
|
||||
// error loading
|
||||
Log::Warning("Failed to load Session file %s.", filename.c_str());
|
||||
}
|
||||
|
||||
sessionThreadActive_ = false;
|
||||
}
|
||||
|
||||
static std::atomic<bool> sessionImportRequested_ = false;
|
||||
static void importSession(const std::string& filename, Session *session)
|
||||
{
|
||||
while (sessionThreadActive_)
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds(50));
|
||||
sessionThreadActive_ = true;
|
||||
|
||||
// actual loading of xml file
|
||||
SessionCreator creator( session );
|
||||
|
||||
if (creator.load(filename)) {
|
||||
|
||||
// internal update flag
|
||||
sessionImportRequested_ = true;
|
||||
|
||||
Log::Notify("Session %s loaded. %d source(s) imported.", filename.c_str(), session->numSource());
|
||||
}
|
||||
else {
|
||||
// error loading
|
||||
Log::Warning("Failed to import Session file %s.", filename.c_str());
|
||||
}
|
||||
|
||||
sessionThreadActive_ = false;
|
||||
}
|
||||
|
||||
// static multithreaded session saving
|
||||
static void saveSession(const std::string& filename, Session *session)
|
||||
{
|
||||
// reset
|
||||
while (sessionThreadActive_)
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds(50));
|
||||
sessionThreadActive_ = true;
|
||||
|
||||
// creation of XML doc
|
||||
XMLDocument xmlDoc;
|
||||
|
||||
XMLElement *version = xmlDoc.NewElement(APP_NAME);
|
||||
version->SetAttribute("major", XML_VERSION_MAJOR);
|
||||
version->SetAttribute("minor", XML_VERSION_MINOR);
|
||||
version->SetAttribute("size", session->numSource());
|
||||
version->SetAttribute("date", SystemToolkit::date_time_string().c_str());
|
||||
xmlDoc.InsertEndChild(version);
|
||||
|
||||
// 1. list of sources
|
||||
XMLElement *sessionNode = xmlDoc.NewElement("Session");
|
||||
xmlDoc.InsertEndChild(sessionNode);
|
||||
SourceList::iterator iter;
|
||||
for (iter = session->begin(); iter != session->end(); iter++)
|
||||
{
|
||||
SessionVisitor sv(&xmlDoc, sessionNode);
|
||||
// source visitor
|
||||
(*iter)->accept(sv);
|
||||
}
|
||||
|
||||
// 2. config of views
|
||||
XMLElement *views = xmlDoc.NewElement("Views");
|
||||
xmlDoc.InsertEndChild(views);
|
||||
{
|
||||
XMLElement *mixing = xmlDoc.NewElement( "Mixing" );
|
||||
mixing->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::MIXING), &xmlDoc));
|
||||
views->InsertEndChild(mixing);
|
||||
|
||||
XMLElement *geometry = xmlDoc.NewElement( "Geometry" );
|
||||
geometry->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::GEOMETRY), &xmlDoc));
|
||||
views->InsertEndChild(geometry);
|
||||
|
||||
XMLElement *layer = xmlDoc.NewElement( "Layer" );
|
||||
layer->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::LAYER), &xmlDoc));
|
||||
views->InsertEndChild(layer);
|
||||
|
||||
XMLElement *render = xmlDoc.NewElement( "Rendering" );
|
||||
render->InsertEndChild( SessionVisitor::NodeToXML(*session->config(View::RENDERING), &xmlDoc));
|
||||
views->InsertEndChild(render);
|
||||
}
|
||||
|
||||
|
||||
// save file to disk
|
||||
if ( XMLSaveDoc(&xmlDoc, filename) ) {
|
||||
// all ok
|
||||
session->setFilename(filename);
|
||||
// cosmetics saved ok
|
||||
Rendering::manager().mainWindow().setTitle(filename);
|
||||
Settings::application.recentSessions.push(filename);
|
||||
Log::Notify("Session %s saved.", filename.c_str());
|
||||
|
||||
// set session filename
|
||||
}
|
||||
else {
|
||||
// error loading
|
||||
Log::Warning("Failed to save Session file %s.", filename.c_str());
|
||||
}
|
||||
|
||||
sessionThreadActive_ = false;
|
||||
}
|
||||
|
||||
Mixer::Mixer() : session_(nullptr), back_session_(nullptr), current_view_(nullptr),
|
||||
update_time_(GST_CLOCK_TIME_NONE), dt_(0.f)
|
||||
{
|
||||
// unsused initial empty session
|
||||
session_ = new Session;
|
||||
current_source_ = session_->end();
|
||||
current_source_index_ = -1;
|
||||
|
||||
// auto load if Settings ask to
|
||||
if ( Settings::application.recentSessions.load_at_start &&
|
||||
Settings::application.recentSessions.valid_file &&
|
||||
Settings::application.recentSessions.filenames.size() > 0 )
|
||||
load( Settings::application.recentSessions.filenames.front() );
|
||||
else
|
||||
// initializes with a new empty session
|
||||
clear();
|
||||
|
||||
// this initializes with the current view
|
||||
setView( (View::Mode) Settings::application.current_view );
|
||||
}
|
||||
|
||||
void Mixer::update()
|
||||
{
|
||||
// change session when threaded loading is finished
|
||||
if (sessionSwapRequested_) {
|
||||
sessionSwapRequested_ = false;
|
||||
// successfully loading
|
||||
if ( back_session_ ) {
|
||||
// swap front and back sessions
|
||||
swap();
|
||||
// set session filename
|
||||
Rendering::manager().mainWindow().setTitle(session_->filename());
|
||||
Settings::application.recentSessions.push(session_->filename());
|
||||
}
|
||||
}
|
||||
// merge session when threaded loading is finished
|
||||
if (sessionImportRequested_) {
|
||||
sessionImportRequested_ = false;
|
||||
merge(back_session_);
|
||||
back_session_ = nullptr;
|
||||
}
|
||||
|
||||
// insert source candidate for this session
|
||||
if (candidate_sources_.size() > 0) {
|
||||
// NB: only make the last candidate the current source in Mixing view
|
||||
insertSource(candidate_sources_.front(), candidate_sources_.size() > 1 ? View::INVALID : View::MIXING);
|
||||
candidate_sources_.pop_front();
|
||||
}
|
||||
|
||||
// compute dt
|
||||
if (update_time_ == GST_CLOCK_TIME_NONE)
|
||||
update_time_ = gst_util_get_timestamp ();
|
||||
guint64 current_time = gst_util_get_timestamp ();
|
||||
// dt is in milisecond, with fractional precision (from micro seconds)
|
||||
dt_ = static_cast<float>( GST_TIME_AS_USECONDS(current_time - update_time_) * 0.001f);
|
||||
update_time_ = current_time;
|
||||
|
||||
// update session and associated sources
|
||||
session_->update(dt_);
|
||||
|
||||
// delete sources which failed update (one by one)
|
||||
if (session()->failedSource() != nullptr)
|
||||
deleteSource(session()->failedSource());
|
||||
|
||||
// update views
|
||||
mixing_.update(dt_);
|
||||
geometry_.update(dt_);
|
||||
layer_.update(dt_);
|
||||
transition_.update(dt_);
|
||||
|
||||
// deep updates shall be performed only 1 frame
|
||||
View::need_deep_update_ = false;
|
||||
}
|
||||
|
||||
void Mixer::draw()
|
||||
{
|
||||
// draw the current view in the window
|
||||
current_view_->draw();
|
||||
|
||||
}
|
||||
|
||||
// manangement of sources
|
||||
Source * Mixer::createSourceFile(std::string path)
|
||||
{
|
||||
// ready to create a source
|
||||
Source *s = nullptr;
|
||||
|
||||
// sanity check
|
||||
if ( SystemToolkit::file_exists( path ) ) {
|
||||
|
||||
// test type of file by extension
|
||||
std::string ext = SystemToolkit::extension_filename(path);
|
||||
if ( ext == "mix" )
|
||||
{
|
||||
// create a session source
|
||||
SessionSource *ss = new SessionSource();
|
||||
ss->load(path);
|
||||
s = ss;
|
||||
}
|
||||
else {
|
||||
// (try to) create media source by default
|
||||
MediaSource *ms = new MediaSource;
|
||||
ms->setPath(path);
|
||||
s = ms;
|
||||
}
|
||||
|
||||
// remember in recent media
|
||||
Settings::application.recentImport.push(path);
|
||||
Settings::application.recentImport.path = SystemToolkit::path_filename(path);
|
||||
|
||||
// propose a new name based on uri
|
||||
renameSource(s, SystemToolkit::base_filename(path));
|
||||
|
||||
}
|
||||
else
|
||||
Log::Notify("File %s does not exist.", path.c_str());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Source * Mixer::createSourceRender()
|
||||
{
|
||||
// ready to create a source
|
||||
RenderSource *s = new RenderSource(session_);
|
||||
|
||||
// propose a new name based on session name
|
||||
renameSource(s, SystemToolkit::base_filename(session_->filename()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Source * Mixer::createSourceClone(std::string namesource)
|
||||
{
|
||||
// ready to create a source
|
||||
Source *s = nullptr;
|
||||
|
||||
// origin to clone is either the given name or the current
|
||||
SourceList::iterator origin = session_->end();
|
||||
if ( !namesource.empty() )
|
||||
origin =session_->find(namesource);
|
||||
else if (current_source_ != session_->end())
|
||||
origin = current_source_;
|
||||
|
||||
// have an origin, can clone it
|
||||
if (origin != session_->end()) {
|
||||
|
||||
// create a source
|
||||
s = (*origin)->clone();
|
||||
|
||||
// get new name
|
||||
renameSource(s, (*origin)->name());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void Mixer::addSource(Source *s)
|
||||
{
|
||||
if (s != nullptr)
|
||||
candidate_sources_.push_back(s);
|
||||
}
|
||||
|
||||
void Mixer::insertSource(Source *s, View::Mode m)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// Add source to Session
|
||||
SourceList::iterator sit = session_->addSource(s);
|
||||
|
||||
// set a default depth to the new source
|
||||
layer_.setDepth(s);
|
||||
|
||||
// set a default alpha to the new source
|
||||
mixing_.setAlpha(s);
|
||||
|
||||
// add sources Nodes to all views
|
||||
mixing_.scene.ws()->attach(s->group(View::MIXING));
|
||||
geometry_.scene.ws()->attach(s->group(View::GEOMETRY));
|
||||
layer_.scene.ws()->attach(s->group(View::LAYER));
|
||||
|
||||
// if requested to show the source in a given view
|
||||
// (known to work for View::MIXING et TRANSITION: other views untested)
|
||||
if (m != View::INVALID) {
|
||||
|
||||
// switch to this view to show source created
|
||||
setView(m);
|
||||
current_view_->update(0.f);
|
||||
current_view_->centerSource(s);
|
||||
|
||||
// set this new source as current
|
||||
setCurrentSource( sit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::deleteSource(Source *s)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// in case it was the current source...
|
||||
unsetCurrentSource();
|
||||
|
||||
// in case it was selected..
|
||||
selection().remove(s);
|
||||
|
||||
// keep name for log
|
||||
std::string name = s->name();
|
||||
|
||||
// remove source Nodes from all views
|
||||
mixing_.scene.ws()->detatch( s->group(View::MIXING) );
|
||||
geometry_.scene.ws()->detatch( s->group(View::GEOMETRY) );
|
||||
layer_.scene.ws()->detatch( s->group(View::LAYER) );
|
||||
transition_.scene.ws()->detatch( s->group(View::TRANSITION) );
|
||||
|
||||
// delete source
|
||||
session_->deleteSource(s);
|
||||
|
||||
// log
|
||||
Log::Notify("Source %s deleted.", name.c_str());
|
||||
}
|
||||
|
||||
// cancel transition source in TRANSITION view
|
||||
if ( current_view_ == &transition_ ) {
|
||||
// cancel attachment
|
||||
transition_.attach(nullptr);
|
||||
// revert to mixing view
|
||||
setView(View::MIXING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mixer::deleteSelection()
|
||||
{
|
||||
while ( !selection().empty() )
|
||||
deleteSource( selection().front());
|
||||
|
||||
}
|
||||
|
||||
void Mixer::renameSource(Source *s, const std::string &newname)
|
||||
{
|
||||
if ( s != nullptr )
|
||||
{
|
||||
// tentative new name
|
||||
std::string tentativename = newname;
|
||||
|
||||
// refuse to rename to an empty name
|
||||
if ( newname.empty() )
|
||||
tentativename = "source";
|
||||
|
||||
// trivial case : same name as current
|
||||
if ( tentativename == s->name() )
|
||||
return;
|
||||
|
||||
// search for a source of the name 'tentativename'
|
||||
std::string basename = tentativename;
|
||||
int count = 1;
|
||||
while ( std::find_if(session_->begin(), session_->end(), Source::hasName(tentativename)) != session_->end() ) {
|
||||
tentativename = basename + std::to_string(++count);
|
||||
}
|
||||
|
||||
// ok to rename
|
||||
s->setName(tentativename);
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::setCurrentSource(SourceList::iterator it)
|
||||
{
|
||||
// nothing to do if already current
|
||||
if ( current_source_ == it )
|
||||
return;
|
||||
|
||||
// clear current (even if it is invalid)
|
||||
unsetCurrentSource();
|
||||
|
||||
// change current if it is valid
|
||||
if ( it != session_->end() ) {
|
||||
current_source_ = it;
|
||||
current_source_index_ = session_->index(current_source_);
|
||||
|
||||
// set selection for this only source if not already part of a selection
|
||||
if (!selection().contains(*current_source_))
|
||||
selection().set(*current_source_);
|
||||
|
||||
// show status as current
|
||||
(*current_source_)->setMode(Source::CURRENT);
|
||||
|
||||
(*current_source_)->group(View::MIXING)->update_callbacks_.push_back(new BounceScaleCallback);
|
||||
(*current_source_)->group(View::LAYER)->update_callbacks_.push_back(new BounceScaleCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Source * Mixer::findSource (Node *node)
|
||||
{
|
||||
SourceList::iterator it = session_->find(node);
|
||||
if (it != session_->end())
|
||||
return *it;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Source * Mixer::findSource (std::string namesource)
|
||||
{
|
||||
SourceList::iterator it = session_->find(namesource);
|
||||
if (it != session_->end())
|
||||
return *it;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Mixer::setCurrentSource(Node *node)
|
||||
{
|
||||
setCurrentSource( session_->find(node) );
|
||||
}
|
||||
|
||||
void Mixer::setCurrentSource(std::string namesource)
|
||||
{
|
||||
setCurrentSource( session_->find(namesource) );
|
||||
}
|
||||
|
||||
void Mixer::setCurrentSource(Source *s)
|
||||
{
|
||||
setCurrentSource( session_->find(s) );
|
||||
}
|
||||
|
||||
void Mixer::setCurrentSource(int index)
|
||||
{
|
||||
setCurrentSource( session_->find(index) );
|
||||
}
|
||||
|
||||
void Mixer::setCurrentNext()
|
||||
{
|
||||
SourceList::iterator it = current_source_;
|
||||
|
||||
it++;
|
||||
|
||||
if (it == session_->end()) {
|
||||
it = session_->begin();
|
||||
}
|
||||
|
||||
setCurrentSource( it );
|
||||
}
|
||||
|
||||
void Mixer::unsetCurrentSource()
|
||||
{
|
||||
// discard overlay for previously current source
|
||||
if ( current_source_ != session_->end() ) {
|
||||
|
||||
// current source is part of a selection, just change status
|
||||
if (selection().size() > 1) {
|
||||
(*current_source_)->setMode(Source::SELECTED);
|
||||
}
|
||||
// current source is the only selected source, unselect too
|
||||
else
|
||||
{
|
||||
// remove from selection
|
||||
selection().remove( *current_source_ );
|
||||
}
|
||||
|
||||
// deselect current source
|
||||
current_source_ = session_->end();
|
||||
current_source_index_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int Mixer::indexCurrentSource()
|
||||
{
|
||||
return current_source_index_;
|
||||
}
|
||||
|
||||
Source *Mixer::currentSource()
|
||||
{
|
||||
if ( current_source_ == session_->end() )
|
||||
return nullptr;
|
||||
else {
|
||||
return *(current_source_);
|
||||
}
|
||||
}
|
||||
|
||||
// management of view
|
||||
void Mixer::setView(View::Mode m)
|
||||
{
|
||||
// special case when leaving transition view
|
||||
if ( current_view_ == &transition_ ) {
|
||||
// get the session detached from the transition view and set it as current session
|
||||
// NB: detatch() can return nullptr, which is then ignored.
|
||||
set ( transition_.detach() );
|
||||
}
|
||||
|
||||
switch (m) {
|
||||
case View::TRANSITION:
|
||||
current_view_ = &transition_;
|
||||
break;
|
||||
case View::GEOMETRY:
|
||||
current_view_ = &geometry_;
|
||||
break;
|
||||
case View::LAYER:
|
||||
current_view_ = &layer_;
|
||||
break;
|
||||
case View::MIXING:
|
||||
default:
|
||||
current_view_ = &mixing_;
|
||||
break;
|
||||
}
|
||||
|
||||
// need to deeply update view to apply eventual changes
|
||||
View::need_deep_update_ = true;
|
||||
|
||||
Settings::application.current_view = (int) m;
|
||||
}
|
||||
|
||||
View *Mixer::view(View::Mode m)
|
||||
{
|
||||
switch (m) {
|
||||
case View::TRANSITION:
|
||||
return &transition_;
|
||||
case View::GEOMETRY:
|
||||
return &geometry_;
|
||||
case View::LAYER:
|
||||
return &layer_;
|
||||
case View::MIXING:
|
||||
return &mixing_;
|
||||
default:
|
||||
return current_view_;
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::save()
|
||||
{
|
||||
if (!session_->filename().empty())
|
||||
saveas(session_->filename());
|
||||
}
|
||||
|
||||
void Mixer::saveas(const std::string& filename)
|
||||
{
|
||||
// optional copy of views config
|
||||
session_->config(View::MIXING)->copyTransform( mixing_.scene.root() );
|
||||
session_->config(View::GEOMETRY)->copyTransform( geometry_.scene.root() );
|
||||
session_->config(View::LAYER)->copyTransform( layer_.scene.root() );
|
||||
|
||||
// launch a thread to save the session
|
||||
std::thread (saveSession, filename, session_).detach();
|
||||
}
|
||||
|
||||
void Mixer::load(const std::string& filename)
|
||||
{
|
||||
if (back_session_)
|
||||
delete back_session_;
|
||||
|
||||
// create empty session
|
||||
back_session_ = new Session;
|
||||
|
||||
// launch a thread to load the session into back_session
|
||||
std::thread (loadSession, filename, back_session_).detach();
|
||||
}
|
||||
|
||||
void Mixer::open(const std::string& filename)
|
||||
{
|
||||
if (Settings::application.smooth_transition)
|
||||
{
|
||||
// create special SessionSource to be used for the smooth transition
|
||||
SessionSource *ts = new SessionSource();
|
||||
// open filename if specified
|
||||
if (!filename.empty())
|
||||
ts->load(filename);
|
||||
// propose a new name based on uri
|
||||
renameSource(ts, SystemToolkit::base_filename(filename));
|
||||
|
||||
// insert source and switch to transition view
|
||||
insertSource(ts, View::TRANSITION);
|
||||
|
||||
// attach the SessionSource to the transition view
|
||||
transition_.attach(ts);
|
||||
}
|
||||
else
|
||||
load(filename);
|
||||
}
|
||||
|
||||
void Mixer::import(const std::string& filename)
|
||||
{
|
||||
if (back_session_)
|
||||
delete back_session_;
|
||||
|
||||
// create empty session
|
||||
back_session_ = new Session;
|
||||
|
||||
// launch a thread to load the session into back_session
|
||||
std::thread (importSession, filename, back_session_).detach();
|
||||
}
|
||||
|
||||
void Mixer::merge(Session *session)
|
||||
{
|
||||
if (session) {
|
||||
|
||||
for ( Source *s = session->popSource(); s != nullptr; s = session->popSource())
|
||||
insertSource(s);
|
||||
|
||||
delete session;
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::swap()
|
||||
{
|
||||
if (!back_session_)
|
||||
return;
|
||||
|
||||
if (session_) {
|
||||
// clear selection
|
||||
selection().clear();
|
||||
// detatch current session's nodes from views
|
||||
for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++)
|
||||
{
|
||||
mixing_.scene.ws()->detatch( (*source_iter)->group(View::MIXING) );
|
||||
geometry_.scene.ws()->detatch( (*source_iter)->group(View::GEOMETRY) );
|
||||
layer_.scene.ws()->detatch( (*source_iter)->group(View::LAYER) );
|
||||
transition_.scene.ws()->detatch( (*source_iter)->group(View::TRANSITION) );
|
||||
}
|
||||
}
|
||||
|
||||
// swap back and front
|
||||
Session *tmp = session_;
|
||||
session_ = back_session_;
|
||||
back_session_ = tmp;
|
||||
|
||||
// swap recorders
|
||||
back_session_->transferRecorders(session_);
|
||||
|
||||
// attach new session's nodes to views
|
||||
for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++)
|
||||
{
|
||||
mixing_.scene.ws()->attach( (*source_iter)->group(View::MIXING) );
|
||||
geometry_.scene.ws()->attach( (*source_iter)->group(View::GEOMETRY) );
|
||||
layer_.scene.ws()->attach( (*source_iter)->group(View::LAYER) );
|
||||
}
|
||||
|
||||
// optional copy of views config
|
||||
mixing_.scene.root()->copyTransform( session_->config(View::MIXING) );
|
||||
geometry_.scene.root()->copyTransform( session_->config(View::GEOMETRY) );
|
||||
layer_.scene.root()->copyTransform( session_->config(View::LAYER) );
|
||||
|
||||
// set resolution
|
||||
session_->setResolution( session_->config(View::RENDERING)->scale_ );
|
||||
|
||||
// transfer fading
|
||||
session_->setFading( MAX(back_session_->fading(), session_->fading()), true );
|
||||
|
||||
// request complete update for views
|
||||
View::need_deep_update_ = true;
|
||||
|
||||
// no current source
|
||||
current_source_ = session_->end();
|
||||
current_source_index_ = -1;
|
||||
|
||||
// reset timer
|
||||
update_time_ = GST_CLOCK_TIME_NONE;
|
||||
|
||||
// delete back
|
||||
delete back_session_;
|
||||
back_session_ = nullptr;
|
||||
}
|
||||
|
||||
void Mixer::close()
|
||||
{
|
||||
if (Settings::application.smooth_transition)
|
||||
{
|
||||
// create empty SessionSource to be used for the smooth transition
|
||||
SessionSource *ts = new SessionSource();
|
||||
|
||||
// insert source and switch to transition view
|
||||
insertSource(ts, View::TRANSITION);
|
||||
|
||||
// attach the SessionSource to the transition view
|
||||
transition_.attach(ts);
|
||||
}
|
||||
else
|
||||
clear();
|
||||
}
|
||||
|
||||
void Mixer::clear()
|
||||
{
|
||||
// delete previous back session if needed
|
||||
if (back_session_)
|
||||
delete back_session_;
|
||||
|
||||
// create empty session
|
||||
back_session_ = new Session;
|
||||
|
||||
// swap current with empty
|
||||
sessionSwapRequested_ = true;
|
||||
|
||||
Log::Info("New session ready.");
|
||||
}
|
||||
|
||||
void Mixer::set(Session *s)
|
||||
{
|
||||
if ( s == nullptr )
|
||||
return;
|
||||
|
||||
// delete previous back session if needed
|
||||
if (back_session_)
|
||||
delete back_session_;
|
||||
|
||||
// set to new given session
|
||||
back_session_ = s;
|
||||
|
||||
// swap current with given session
|
||||
sessionSwapRequested_ = true;
|
||||
}
|
||||
104
Mixer.h
@@ -1,104 +0,0 @@
|
||||
#ifndef MIXER_H
|
||||
#define MIXER_H
|
||||
|
||||
#include "View.h"
|
||||
#include "Session.h"
|
||||
#include "Selection.h"
|
||||
|
||||
class Mixer
|
||||
{
|
||||
// Private Constructor
|
||||
Mixer();
|
||||
Mixer(Mixer const& copy); // Not Implemented
|
||||
Mixer& operator=(Mixer const& copy); // Not Implemented
|
||||
|
||||
public:
|
||||
|
||||
static Mixer& manager()
|
||||
{
|
||||
// The only instance
|
||||
static Mixer _instance;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static Selection& selection()
|
||||
{
|
||||
// The only instance
|
||||
static Selection _selection;
|
||||
return _selection;
|
||||
}
|
||||
|
||||
// update session and all views
|
||||
void update();
|
||||
inline float dt() const { return dt_;}
|
||||
|
||||
// draw session and current view
|
||||
void draw();
|
||||
|
||||
// creation of sources
|
||||
Source * createSourceFile (std::string path);
|
||||
Source * createSourceClone (std::string namesource = "");
|
||||
Source * createSourceRender ();
|
||||
|
||||
// operations on sources
|
||||
void addSource (Source *s);
|
||||
void deleteSource (Source *s);
|
||||
void renameSource (Source *s, const std::string &newname);
|
||||
void deleteSelection();
|
||||
|
||||
// current source
|
||||
void setCurrentSource (Source *s);
|
||||
void setCurrentSource (std::string namesource);
|
||||
void setCurrentSource (Node *node);
|
||||
void setCurrentSource (int index);
|
||||
void setCurrentNext ();
|
||||
void unsetCurrentSource ();
|
||||
int indexCurrentSource ();
|
||||
Source * currentSource ();
|
||||
|
||||
// browsing into sources
|
||||
Source * findSource (Node *node);
|
||||
Source * findSource (std::string name);
|
||||
|
||||
// management of view
|
||||
View *view (View::Mode m = View::INVALID);
|
||||
void setView (View::Mode m);
|
||||
|
||||
// manipulate, load and save sessions
|
||||
inline Session *session () const { return session_; }
|
||||
void clear ();
|
||||
void save ();
|
||||
void saveas (const std::string& filename);
|
||||
void load (const std::string& filename);
|
||||
void import (const std::string& filename);
|
||||
void merge (Session *s);
|
||||
void set (Session *s);
|
||||
|
||||
// operations depending on transition mode
|
||||
void close ();
|
||||
void open (const std::string& filename);
|
||||
|
||||
protected:
|
||||
|
||||
Session *session_;
|
||||
Session *back_session_;
|
||||
void swap();
|
||||
|
||||
SourceList candidate_sources_;
|
||||
void insertSource(Source *s, View::Mode m = View::INVALID);
|
||||
|
||||
void setCurrentSource(SourceList::iterator it);
|
||||
SourceList::iterator current_source_;
|
||||
int current_source_index_;
|
||||
|
||||
View *current_view_;
|
||||
MixingView mixing_;
|
||||
GeometryView geometry_;
|
||||
LayerView layer_;
|
||||
TransitionView transition_;
|
||||
|
||||
guint64 update_time_;
|
||||
float dt_;
|
||||
};
|
||||
|
||||
#endif // MIXER_H
|
||||
@@ -1,163 +0,0 @@
|
||||
#include "PickingVisitor.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Primitives.h"
|
||||
#include "Decorations.h"
|
||||
|
||||
#include "GlmToolkit.h"
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
|
||||
PickingVisitor::PickingVisitor(glm::vec3 coordinates) : Visitor()
|
||||
{
|
||||
modelview_ = glm::mat4(1.f);
|
||||
points_.push_back( coordinates );
|
||||
}
|
||||
|
||||
PickingVisitor::PickingVisitor(glm::vec3 selectionstart, glm::vec3 selection_end) : Visitor()
|
||||
{
|
||||
modelview_ = glm::mat4(1.f);
|
||||
points_.push_back( selectionstart );
|
||||
points_.push_back( selection_end );
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Node &n)
|
||||
{
|
||||
// use the transform modified during update
|
||||
modelview_ *= n.transform_;
|
||||
|
||||
// modelview_ *= transform(n.translation_, n.rotation_, n.scale_);
|
||||
// Log::Info("Node %d", n.id());
|
||||
// Log::Info("%s", glm::to_string(modelview_).c_str());
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Group &n)
|
||||
{
|
||||
if (!n.visible_)
|
||||
return;
|
||||
|
||||
glm::mat4 mv = modelview_;
|
||||
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||
if ( (*node)->visible_ )
|
||||
(*node)->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Switch &n)
|
||||
{
|
||||
if (!n.visible_ || n.numChildren()<1)
|
||||
return;
|
||||
|
||||
glm::mat4 mv = modelview_;
|
||||
n.activeChild()->accept(*this);
|
||||
modelview_ = mv;
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Primitive &)
|
||||
{
|
||||
// by default, a Primitive is not interactive
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Surface &n)
|
||||
{
|
||||
if (!n.visible_)
|
||||
return;
|
||||
|
||||
// if more than one point given for testing: test overlap
|
||||
if (points_.size() > 1) {
|
||||
// create bounding box for those points (2 in practice)
|
||||
GlmToolkit::AxisAlignedBoundingBox bb_points;
|
||||
bb_points.extend(points_);
|
||||
|
||||
// apply inverse transform
|
||||
bb_points = bb_points.transformed(glm::inverse(modelview_)) ;
|
||||
|
||||
// test bounding box for overlap with inverse transform bbox
|
||||
if ( bb_points.intersect( n.bbox() ) )
|
||||
// if ( n.bbox().contains( bb_points ) )
|
||||
// add this surface to the nodes picked
|
||||
nodes_.push_back( std::pair(&n, glm::vec2(0.f)) );
|
||||
}
|
||||
// only one point
|
||||
else if (points_.size() > 0) {
|
||||
|
||||
// apply inverse transform to the point of interest
|
||||
glm::vec4 P = glm::inverse(modelview_) * glm::vec4( points_[0], 1.f );
|
||||
|
||||
// test bounding box for picking from a single point
|
||||
if ( n.bbox().contains( glm::vec3(P)) )
|
||||
// add this surface to the nodes picked
|
||||
nodes_.push_back( std::pair(&n, glm::vec2(P)) );
|
||||
}
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Disk &n)
|
||||
{
|
||||
// discard if not visible or if not exactly one point given for picking
|
||||
if (!n.visible_ || points_.size() != 1)
|
||||
return;
|
||||
|
||||
// apply inverse transform to the point of interest
|
||||
glm::vec4 P = glm::inverse(modelview_) * glm::vec4( points_[0], 1.f );
|
||||
|
||||
// test distance for picking from a single point
|
||||
if ( glm::length(glm::vec2(P)) < 1.f )
|
||||
// add this surface to the nodes picked
|
||||
nodes_.push_back( std::pair(&n, glm::vec2(P)) );
|
||||
|
||||
}
|
||||
|
||||
void PickingVisitor::visit(Handles &n)
|
||||
{
|
||||
// discard if not visible or if not exactly one point given for picking
|
||||
if (!n.visible_ || points_.size() != 1)
|
||||
return;
|
||||
|
||||
// apply inverse transform to the point of interest
|
||||
glm::vec4 P = glm::inverse(modelview_) * glm::vec4( points_[0], 1.f );
|
||||
|
||||
// inverse transform to check the scale
|
||||
glm::vec4 S = glm::inverse(modelview_) * glm::vec4( 0.05f, 0.05f, 0.f, 0.f );
|
||||
float scale = glm::length( glm::vec2(S) );
|
||||
|
||||
bool picked = false;
|
||||
if ( n.type() == Handles::RESIZE ) {
|
||||
// 4 corners
|
||||
picked = ( glm::length(glm::vec2(+1.f, +1.f)- glm::vec2(P)) < scale ||
|
||||
glm::length(glm::vec2(+1.f, -1.f)- glm::vec2(P)) < scale ||
|
||||
glm::length(glm::vec2(-1.f, +1.f)- glm::vec2(P)) < scale ||
|
||||
glm::length(glm::vec2(-1.f, -1.f)- glm::vec2(P)) < scale );
|
||||
}
|
||||
else if ( n.type() == Handles::RESIZE_H ){
|
||||
// left & right
|
||||
picked = ( glm::length(glm::vec2(+1.f, 0.f)- glm::vec2(P)) < scale ||
|
||||
glm::length(glm::vec2(-1.f, 0.f)- glm::vec2(P)) < scale );
|
||||
}
|
||||
else if ( n.type() == Handles::RESIZE_V ){
|
||||
// top & bottom
|
||||
picked = ( glm::length(glm::vec2(0.f, +1.f)- glm::vec2(P)) < scale ||
|
||||
glm::length(glm::vec2(0.f, -1.f)- glm::vec2(P)) < scale );
|
||||
}
|
||||
else if ( n.type() == Handles::ROTATE ){
|
||||
// the icon for rotation is on the right top corner at (0.12, 0.12) in scene coordinates
|
||||
glm::vec4 vec = glm::inverse(modelview_) * glm::vec4( 0.1f, 0.1f, 0.f, 0.f );
|
||||
float l = glm::length( glm::vec2(vec) );
|
||||
picked = glm::length( glm::vec2( 1.f + l, 1.f + l) - glm::vec2(P) ) < 1.5f * scale;
|
||||
}
|
||||
|
||||
if ( picked )
|
||||
// add this to the nodes picked
|
||||
nodes_.push_back( std::pair(&n, glm::vec2(P)) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PickingVisitor::visit(Scene &n)
|
||||
{
|
||||
n.root()->accept(*this);
|
||||
}
|
||||
391
Primitives.cpp
@@ -1,391 +0,0 @@
|
||||
#include "Primitives.h"
|
||||
#include "ImageShader.h"
|
||||
#include "Resource.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "MediaPlayer.h"
|
||||
#include "Visitor.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/rotate_vector.hpp>
|
||||
|
||||
|
||||
|
||||
Surface::Surface(Shader *s) : Primitive(s), textureindex_(0)
|
||||
{
|
||||
// geometry for a trianglulated simple rectangle surface with UV
|
||||
// (0,0) B +---+ D (1,0)
|
||||
// |\ |
|
||||
// | \ |
|
||||
// | \|
|
||||
// (0,1) A +---+ C (1,1)
|
||||
|
||||
points_ = std::vector<glm::vec3> { glm::vec3( -1.f, -1.f, 0.f ), glm::vec3( -1.f, 1.f, 0.f ),
|
||||
glm::vec3( 1.f, -1.f, 0.f ), glm::vec3( 1.f, 1.f, 0.f ) };
|
||||
colors_ = std::vector<glm::vec4> { glm::vec4( 1.f, 1.f, 1.f , 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ),
|
||||
glm::vec4( 1.f, 1.f, 1.f, 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ) };
|
||||
texCoords_ = std::vector<glm::vec2> { glm::vec2( 0.f, 1.f ), glm::vec2( 0.f, 0.f ),
|
||||
glm::vec2( 1.f, 1.f ), glm::vec2( 1.f, 0.f ) };
|
||||
indices_ = std::vector<uint> { 0, 1, 2, 3 };
|
||||
drawMode_ = GL_TRIANGLE_STRIP;
|
||||
}
|
||||
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
// do NOT delete vao_ (unique)
|
||||
vao_ = 0;
|
||||
}
|
||||
|
||||
void Surface::init()
|
||||
{
|
||||
// use static unique vertex array object
|
||||
static uint unique_vao_ = 0;
|
||||
static uint unique_drawCount = 0;
|
||||
if (unique_vao_) {
|
||||
// 1. only init Node (not the primitive vao)
|
||||
Node::init();
|
||||
// 2. use the global vertex array object
|
||||
vao_ = unique_vao_;
|
||||
drawCount_ = unique_drawCount;
|
||||
// compute AxisAlignedBoundingBox
|
||||
bbox_.extend(points_);
|
||||
// arrays of vertices are not needed anymore
|
||||
points_.clear();
|
||||
colors_.clear();
|
||||
texCoords_.clear();
|
||||
indices_.clear();
|
||||
}
|
||||
else {
|
||||
// 1. init the Primitive (only once)
|
||||
Primitive::init();
|
||||
// 2. remember global vertex array object
|
||||
unique_vao_ = vao_;
|
||||
unique_drawCount = drawCount_;
|
||||
// 3. unique_vao_ will NOT be deleted
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Surface::accept(Visitor& v)
|
||||
{
|
||||
Primitive::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
void Surface::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() )
|
||||
init();
|
||||
|
||||
if ( textureindex_ )
|
||||
glBindTexture(GL_TEXTURE_2D, textureindex_);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, Resource::getTextureBlack());
|
||||
|
||||
Primitive::draw(modelview, projection);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
ImageSurface::ImageSurface(const std::string& path, Shader *s) : Surface(s), resource_(path)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ImageSurface::init()
|
||||
{
|
||||
Surface::init();
|
||||
|
||||
// load image if specified (should always be the case)
|
||||
if ( !resource_.empty()) {
|
||||
textureindex_ = Resource::getTextureImage(resource_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSurface::accept(Visitor& v)
|
||||
{
|
||||
Surface::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
MediaSurface::MediaSurface(const std::string& p, Shader *s) : Surface(s)
|
||||
{
|
||||
path_ = p;
|
||||
mediaplayer_ = new MediaPlayer;
|
||||
}
|
||||
|
||||
MediaSurface::~MediaSurface()
|
||||
{
|
||||
delete mediaplayer_;
|
||||
}
|
||||
|
||||
void MediaSurface::init()
|
||||
{
|
||||
Surface::init();
|
||||
|
||||
mediaplayer_->open(path_);
|
||||
mediaplayer_->play(true);
|
||||
}
|
||||
|
||||
void MediaSurface::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() )
|
||||
init();
|
||||
|
||||
// set the texture to the media player once openned
|
||||
// TODO: avoid to repeat with a static flag?
|
||||
if ( mediaplayer_->isOpen() )
|
||||
textureindex_ = mediaplayer_->texture();
|
||||
|
||||
Surface::draw(modelview, projection);
|
||||
}
|
||||
|
||||
void MediaSurface::update( float dt )
|
||||
{
|
||||
if ( mediaplayer_->isOpen() ) {
|
||||
mediaplayer_->update();
|
||||
scale_.x = mediaplayer_->aspectRatio();
|
||||
}
|
||||
|
||||
Primitive::update( dt );
|
||||
}
|
||||
|
||||
void MediaSurface::accept(Visitor& v)
|
||||
{
|
||||
Surface::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
FrameBufferSurface::FrameBufferSurface(FrameBuffer *fb, Shader *s) : Surface(s), frame_buffer_(fb)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FrameBufferSurface::init()
|
||||
{
|
||||
Surface::init();
|
||||
|
||||
// set aspect ratio
|
||||
scale_.x = frame_buffer_->aspectRatio();
|
||||
|
||||
}
|
||||
|
||||
void FrameBufferSurface::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() )
|
||||
init();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, frame_buffer_->texture());
|
||||
|
||||
Primitive::draw(modelview, projection);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void FrameBufferSurface::accept(Visitor& v)
|
||||
{
|
||||
Surface::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
Points::Points(std::vector<glm::vec3> points, glm::vec4 color, uint pointsize) : Primitive(new Shader)
|
||||
{
|
||||
for(size_t i = 0; i < points.size(); ++i)
|
||||
{
|
||||
points_.push_back( points[i] );
|
||||
colors_.push_back( color );
|
||||
indices_.push_back ( i );
|
||||
}
|
||||
|
||||
drawMode_ = GL_POINTS; // TODO implement drawing of points as Mesh
|
||||
pointsize_ = pointsize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Points::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() )
|
||||
init();
|
||||
|
||||
glPointSize(pointsize_);
|
||||
|
||||
Primitive::draw(modelview, projection);
|
||||
|
||||
glPointSize(1);
|
||||
}
|
||||
|
||||
void Points::accept(Visitor& v)
|
||||
{
|
||||
Primitive::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
LineStrip::LineStrip(std::vector<glm::vec3> points, std::vector<glm::vec4> colors, uint linewidth) : Primitive(new Shader), linewidth_(linewidth)
|
||||
{
|
||||
for(size_t i = 0; i < points.size(); ++i)
|
||||
{
|
||||
points_.push_back( points[i] );
|
||||
colors_.push_back( colors[i] );
|
||||
indices_.push_back ( i );
|
||||
}
|
||||
|
||||
drawMode_ = GL_LINE_STRIP;
|
||||
}
|
||||
|
||||
void LineStrip::draw(glm::mat4 modelview, glm::mat4 projection)
|
||||
{
|
||||
if ( !initialized() )
|
||||
init();
|
||||
|
||||
// glLineWidth(linewidth_ * 2.f * Rendering::manager().mainWindow().dpiScale());
|
||||
|
||||
glm::mat4 mv = modelview;
|
||||
glm::mat4 scale = glm::scale(glm::identity<glm::mat4>(), glm::vec3(1.001f, 1.001f, 1.f));
|
||||
|
||||
// TODO FIXME drawing multiple times is not correct to draw lines of different width
|
||||
// TODO Draw LineStrip using polygons
|
||||
for (uint i = 0 ; i < linewidth_ ; ++i ) {
|
||||
Primitive::draw(mv, projection);
|
||||
mv *= scale;
|
||||
}
|
||||
|
||||
// glLineWidth(1);
|
||||
}
|
||||
|
||||
void LineStrip::accept(Visitor& v)
|
||||
{
|
||||
Primitive::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const std::vector<glm::vec3> square_points {
|
||||
glm::vec3( -1.f, -1.f, 0.f ), glm::vec3( -1.f, 1.f, 0.f ),
|
||||
glm::vec3( 1.f, 1.f, 0.f ), glm::vec3( 1.f, -1.f, 0.f ),
|
||||
glm::vec3( -1.f, -1.f, 0.f )
|
||||
};
|
||||
|
||||
static const std::vector<glm::vec4> square_colors {
|
||||
glm::vec4( 1.f, 1.f, 1.f, 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ),
|
||||
glm::vec4( 1.f, 1.f, 1.f, 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ),
|
||||
glm::vec4( 1.f, 1.f, 1.f, 1.f )
|
||||
};
|
||||
|
||||
LineSquare::LineSquare(uint linewidth) : LineStrip(square_points, square_colors, linewidth)
|
||||
{
|
||||
}
|
||||
|
||||
void LineSquare::init()
|
||||
{
|
||||
// use static unique vertex array object
|
||||
static uint unique_vao_ = 0;
|
||||
static uint unique_drawCount = 0;
|
||||
if (unique_vao_) {
|
||||
// 1. only init Node (not the primitive vao)
|
||||
Node::init();
|
||||
// 2. use the global vertex array object
|
||||
vao_ = unique_vao_;
|
||||
drawCount_ = unique_drawCount;
|
||||
// compute AxisAlignedBoundingBox
|
||||
bbox_.extend(points_);
|
||||
// arrays of vertices are not needed anymore
|
||||
points_.clear();
|
||||
colors_.clear();
|
||||
texCoords_.clear();
|
||||
indices_.clear();
|
||||
}
|
||||
else {
|
||||
// 1. init the Primitive (only once)
|
||||
Primitive::init();
|
||||
// 2. remember global vertex array object
|
||||
unique_vao_ = vao_;
|
||||
unique_drawCount = drawCount_;
|
||||
}
|
||||
}
|
||||
|
||||
void LineSquare::accept(Visitor& v)
|
||||
{
|
||||
Primitive::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
LineSquare::~LineSquare()
|
||||
{
|
||||
// do NOT delete vao_ (unique)
|
||||
vao_ = 0;
|
||||
}
|
||||
|
||||
|
||||
LineCircle::LineCircle(uint linewidth) : LineStrip(std::vector<glm::vec3>(), std::vector<glm::vec4>(), linewidth)
|
||||
{
|
||||
static int N = 72;
|
||||
static float a = glm::two_pi<float>() / static_cast<float>(N);
|
||||
static glm::vec4 circle_color_points = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
// loop to build a circle
|
||||
glm::vec3 P(1.f, 0.f, 0.f);
|
||||
for (int i = 0; i < N ; i++ ){
|
||||
points_.push_back( glm::vec3(P) );
|
||||
colors_.push_back( circle_color_points );
|
||||
indices_.push_back ( i );
|
||||
|
||||
P = glm::rotateZ(P, a);
|
||||
}
|
||||
// close loop
|
||||
points_.push_back( glm::vec3(1.f, 0.f, 0.f) );
|
||||
colors_.push_back( circle_color_points );
|
||||
indices_.push_back ( N );
|
||||
}
|
||||
|
||||
void LineCircle::init()
|
||||
{
|
||||
// use static unique vertex array object
|
||||
static uint unique_vao_ = 0;
|
||||
static uint unique_drawCount = 0;
|
||||
if (unique_vao_) {
|
||||
// 1. only init Node (not the primitive vao)
|
||||
Node::init();
|
||||
// 2. use the global vertex array object
|
||||
vao_ = unique_vao_;
|
||||
drawCount_ = unique_drawCount;
|
||||
// replace AxisAlignedBoundingBox
|
||||
bbox_.extend(points_);
|
||||
// arrays of vertices are not needed anymore (STATIC DRAW of vertex object)
|
||||
points_.clear();
|
||||
colors_.clear();
|
||||
texCoords_.clear();
|
||||
indices_.clear();
|
||||
}
|
||||
else {
|
||||
// 1. init the Primitive (only once)
|
||||
Primitive::init();
|
||||
// 2. remember global vertex array object
|
||||
unique_vao_ = vao_;
|
||||
unique_drawCount = drawCount_;
|
||||
// 3. unique_vao_ will NOT be deleted because LineCircle::deleteGLBuffers_() is empty
|
||||
}
|
||||
}
|
||||
|
||||
void LineCircle::accept(Visitor& v)
|
||||
{
|
||||
Primitive::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
LineCircle::~LineCircle()
|
||||
{
|
||||
// do NOT delete vao_ (unique)
|
||||
vao_ = 0;
|
||||
}
|
||||
180
Primitives.h
@@ -1,180 +0,0 @@
|
||||
#ifndef PRIMITIVES_H
|
||||
#define PRIMITIVES_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Scene.h"
|
||||
#include "ImageShader.h"
|
||||
|
||||
class MediaPlayer;
|
||||
class FrameBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The Surface class is a Primitive to draw an flat square
|
||||
* surface with texture coordinates.
|
||||
*
|
||||
* It uses a unique vertex array object to draw all surfaces.
|
||||
*
|
||||
*/
|
||||
class Surface : public Primitive {
|
||||
|
||||
public:
|
||||
Surface(Shader *s = new ImageShader);
|
||||
virtual ~Surface();
|
||||
|
||||
void init () override;
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
inline void setTextureIndex(uint t) { textureindex_ = t; }
|
||||
inline uint textureIndex() const { return textureindex_; }
|
||||
|
||||
protected:
|
||||
uint textureindex_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The ImageSurface class is a Surface to draw an image
|
||||
*
|
||||
* It creates an ImageShader for rendering.
|
||||
*
|
||||
* Image is read from the Ressouces (not an external file)
|
||||
* Height = 1.0, Width is set by the aspect ratio of the image
|
||||
*/
|
||||
class ImageSurface : public Surface {
|
||||
|
||||
public:
|
||||
ImageSurface(const std::string& path, Shader *s = new ImageShader);
|
||||
|
||||
void init () override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
inline std::string resource() const { return resource_; }
|
||||
|
||||
protected:
|
||||
std::string resource_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The MediaSurface class is a Surface to draw a video
|
||||
*
|
||||
* URI is passed to a Media Player to handle the video playback
|
||||
* Height = 1.0, Width is set by the aspect ratio of the image
|
||||
*/
|
||||
class MediaSurface : public Surface {
|
||||
|
||||
public:
|
||||
MediaSurface(const std::string& p, Shader *s = new ImageShader);
|
||||
~MediaSurface();
|
||||
|
||||
void init () override;
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
void update (float dt) override;
|
||||
|
||||
inline std::string path() const { return path_; }
|
||||
inline MediaPlayer *mediaPlayer() const { return mediaplayer_; }
|
||||
|
||||
protected:
|
||||
std::string path_;
|
||||
MediaPlayer *mediaplayer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The FrameBufferSurface class is a Surface to draw a framebuffer
|
||||
*
|
||||
* URI is passed to a Media Player to handle the video playback
|
||||
* Height = 1.0, Width is set by the aspect ratio of the image
|
||||
*/
|
||||
class FrameBufferSurface : public Surface {
|
||||
|
||||
public:
|
||||
FrameBufferSurface(FrameBuffer *fb, Shader *s = new ImageShader);
|
||||
|
||||
void init () override;
|
||||
void draw (glm::mat4 modelview, glm::mat4 projection) override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
inline FrameBuffer *getFrameBuffer() const { return frame_buffer_; }
|
||||
|
||||
protected:
|
||||
FrameBuffer *frame_buffer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Points class is a Primitive to draw Points
|
||||
*/
|
||||
class Points : public Primitive {
|
||||
|
||||
uint pointsize_;
|
||||
|
||||
public:
|
||||
Points(std::vector<glm::vec3> points, glm::vec4 color, uint pointsize = 10);
|
||||
|
||||
virtual void draw(glm::mat4 modelview, glm::mat4 projection) override;
|
||||
virtual void accept(Visitor& v) override;
|
||||
|
||||
std::vector<glm::vec3> getPoints() { return points_; }
|
||||
glm::vec4 getColor() { return colors_[0]; }
|
||||
|
||||
inline void setPointSize(uint v) { pointsize_ = v; }
|
||||
inline uint getPointSize() const { return pointsize_; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LineStrip class is a Primitive to draw lines
|
||||
*/
|
||||
class LineStrip : public Primitive {
|
||||
|
||||
uint linewidth_;
|
||||
|
||||
public:
|
||||
LineStrip(std::vector<glm::vec3> points, std::vector<glm::vec4> colors, uint linewidth = 1);
|
||||
|
||||
virtual void draw(glm::mat4 modelview, glm::mat4 projection) override;
|
||||
virtual void accept(Visitor& v) override;
|
||||
|
||||
std::vector<glm::vec3> getPoints() { return points_; }
|
||||
std::vector<glm::vec4> getColors() { return colors_; }
|
||||
|
||||
inline void setLineWidth(uint v) { linewidth_ = v; }
|
||||
inline uint getLineWidth() const { return linewidth_; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LineSquare class is a square LineStrip (width & height = 1.0)
|
||||
*/
|
||||
class LineSquare : public LineStrip {
|
||||
|
||||
public:
|
||||
LineSquare(uint linewidth = 1);
|
||||
|
||||
void init() override;
|
||||
void accept(Visitor& v) override;
|
||||
|
||||
virtual ~LineSquare();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LineCircle class is a circular LineStrip (diameter = 1.0)
|
||||
*/
|
||||
class LineCircle : public LineStrip {
|
||||
|
||||
public:
|
||||
LineCircle(uint linewidth = 1);
|
||||
|
||||
void init() override;
|
||||
void accept(Visitor& v) override;
|
||||
|
||||
virtual ~LineCircle();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // PRIMITIVES_H
|
||||
127
README.md
@@ -1,43 +1,142 @@
|
||||
# vimix
|
||||
Live Video Mixer
|
||||
__Live Video Mixing__
|
||||
|
||||
*/!\ Work in progress*
|
||||
<img src=docs/vimix_screenshot.png width="800">
|
||||
|
||||
v-mix is the successor for GLMixer - https://sourceforge.net/projects/glmixer/
|
||||
|
||||
vimix performs graphical mixing and blending of several movie clips and
|
||||
computer generated graphics, with image processing effects in real-time.
|
||||
|
||||
Its intuitive and hands-on user interface gives direct control on image opacity and
|
||||
shape for producing live graphics during concerts and VJ-ing sessions.
|
||||
|
||||
The output image is typically projected full-screen on an external
|
||||
monitor or a projector, and can be streamed live (SRT, Shmdata) or recorded (without audio).
|
||||
|
||||
vimix is the successor for GLMixer - https://sourceforge.net/projects/glmixer/
|
||||
|
||||
# License
|
||||
|
||||
GPL-3.0-or-later
|
||||
See [LICENSE](https://github.com/brunoherbelin/vimix/blob/master/LICENSE)
|
||||
|
||||
# Install vimix
|
||||
|
||||
Check the [Quick Installation Guide](https://github.com/brunoherbelin/vimix/wiki/Quick-Installation-Guide)
|
||||
|
||||
### Linux
|
||||
|
||||
Download and install a released [flatpak package](https://flathub.org/apps/details/io.github.brunoherbelin.Vimix)
|
||||
|
||||
flatpak install --user vimix
|
||||
|
||||
NB: Building your flatpak package is an option for testing the latest beta version from git ; instructions are [here](https://github.com/brunoherbelin/vimix/tree/master/flatpak).
|
||||
|
||||
|
||||
Download and install a released [snap package](https://snapcraft.io/vimix) (slower release frequency)
|
||||
|
||||
snap install vimix
|
||||
|
||||
Install the stable debian package (slower release frequency)
|
||||
|
||||
sudo apt install vimix
|
||||
|
||||
### Mac OSX
|
||||
|
||||
Download and open a release package from https://github.com/brunoherbelin/vimix/releases
|
||||
|
||||
NB: You'll need to accept the exception in OSX security preference.
|
||||
|
||||
# Build vimix
|
||||
|
||||
## Clone
|
||||
|
||||
git clone --recursive https://github.com/brunoherbelin/vimix.git
|
||||
|
||||
This will create the directory 'vimix', download the latest version of vimix code,
|
||||
and (recursively) clone all the internal git dependencies.
|
||||
|
||||
## Compile
|
||||
|
||||
```
|
||||
cmake -G Ninja
|
||||
ninja
|
||||
```
|
||||
First time after git clone:
|
||||
|
||||
### Dependencies
|
||||
mkdir vimix-build
|
||||
cd vimix-build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ../vimix
|
||||
cmake --build .
|
||||
|
||||
This will create the directory 'vimix-build', configure the program for build, and compile vimix.
|
||||
If successful, the compilation will have produced the executable `vimix` in the `src` directory.
|
||||
You can run vimix with `./src/vimix` :
|
||||
|
||||
...
|
||||
[100%] Built target vimix
|
||||
./src/vimix
|
||||
|
||||
## Update clone and re-compile
|
||||
|
||||
Run these commands from the `vimix-build` directory if you did 'Clone' and 'Compile' previously and only want to get the latest update and rebuild.
|
||||
|
||||
git -C ../vimix/ pull
|
||||
cmake --build .
|
||||
|
||||
This will pull the latest commit from git and recompile.
|
||||
|
||||
## Try the Beta branch
|
||||
|
||||
Run this commands from the `vimix-build` directory before runing 'Update clone and re-compile above'
|
||||
|
||||
git -C ../vimix/ checkout beta
|
||||
|
||||
It should say;
|
||||
|
||||
branch 'beta' set up to track 'origin/beta'.
|
||||
Switched to a new branch 'beta'
|
||||
|
||||
## Dependencies
|
||||
|
||||
**Compiling tools:**
|
||||
|
||||
- gcc
|
||||
- make
|
||||
- cmake
|
||||
- Ninja
|
||||
- git
|
||||
|
||||
**Libraries:**
|
||||
|
||||
- gstreamer
|
||||
- libpng
|
||||
- gst-plugins (libav, base, good, bad & ugly)
|
||||
- libglfw3
|
||||
- libicu (icu-i18n icu-uc icu-io)
|
||||
|
||||
Optionnal:
|
||||
|
||||
- glm
|
||||
- stb
|
||||
- TinyXML2
|
||||
- AbletonLink
|
||||
- Shmdata
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
**tools:**
|
||||
apt-get install build-essential cmake libpng-dev libglfw3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-libav libicu-dev libgtk-3-dev
|
||||
|
||||
apt-get install build-essential cmake ninja-build
|
||||
Optionnal:
|
||||
|
||||
**libs:**
|
||||
apt-get install libglm-dev libstb-dev libtinyxml2-dev ableton-link-dev
|
||||
|
||||
> Follow these instructions to [install Shmdata](https://github.com/nicobou/shmdata/blob/develop/doc/install-from-sources.md).
|
||||
|
||||
git clone https://gitlab.com/sat-metalab/shmdata.git
|
||||
mkdir shmdata-build
|
||||
cd shmdata-build
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_BUILD_TYPE=Release -DWITH_PYTHON=0 -DWITH_SDCRASH=0 -DWITH_SDFLOW=0 ../shmdata-build
|
||||
cmake --build . --target package
|
||||
sudo dpkg -i ./libshmdata_1.3*_amd64.deb
|
||||
|
||||
#### OSX with Brew
|
||||
|
||||
brew install cmake libpng glfw gstreamer icu4c
|
||||
|
||||
apt-get install libpng-dev libglfw3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||
|
||||
491
Recorder.cpp
@@ -1,491 +0,0 @@
|
||||
#include <thread>
|
||||
|
||||
// Desktop OpenGL function loader
|
||||
#include <glad/glad.h>
|
||||
|
||||
// standalone image loader
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
// gstreamer
|
||||
#include <gst/gstformat.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include "Settings.h"
|
||||
#include "GstToolkit.h"
|
||||
#include "defines.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "Recorder.h"
|
||||
|
||||
// use glReadPixel or glGetTextImage
|
||||
// read pixels & pbo should be the fastest
|
||||
// https://stackoverflow.com/questions/38140527/glreadpixels-vs-glgetteximage
|
||||
#define USE_GLREADPIXEL
|
||||
|
||||
using namespace std;
|
||||
|
||||
Recorder::Recorder() : finished_(false), pbo_index_(0), pbo_next_index_(0), size_(0)
|
||||
{
|
||||
pbo_[0] = pbo_[1] = 0;
|
||||
}
|
||||
|
||||
PNGRecorder::PNGRecorder() : Recorder()
|
||||
{
|
||||
std::string path = SystemToolkit::path_directory(Settings::application.record.path);
|
||||
if (path.empty())
|
||||
path = SystemToolkit::home_path();
|
||||
|
||||
filename_ = path + SystemToolkit::date_time_string() + "_vimix.png";
|
||||
|
||||
}
|
||||
|
||||
// Thread to perform slow operation of saving to file
|
||||
void save_png(std::string filename, unsigned char *data, uint w, uint h, uint c)
|
||||
{
|
||||
// got data to save ?
|
||||
if (data) {
|
||||
// save file
|
||||
stbi_write_png(filename.c_str(), w, h, c, data, w * c);
|
||||
// notify
|
||||
Log::Notify("Capture %s ready (%d x %d %d)", filename.c_str(), w, h, c);
|
||||
// done
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void PNGRecorder::addFrame(FrameBuffer *frame_buffer, float)
|
||||
{
|
||||
// ignore
|
||||
if (frame_buffer == nullptr)
|
||||
return;
|
||||
|
||||
// get what is needed from frame buffer
|
||||
uint w = frame_buffer->width();
|
||||
uint h = frame_buffer->height();
|
||||
uint c = frame_buffer->use_alpha() ? 4 : 3;
|
||||
|
||||
// first iteration: initialize and get frame
|
||||
if (size_ < 1)
|
||||
{
|
||||
// init size
|
||||
size_ = w * h * c;
|
||||
|
||||
// create PBO
|
||||
glGenBuffers(2, pbo_);
|
||||
|
||||
// set writing PBO
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[0]);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ);
|
||||
|
||||
#ifdef USE_GLREADPIXEL
|
||||
// get frame
|
||||
frame_buffer->readPixels();
|
||||
#else
|
||||
glBindTexture(GL_TEXTURE_2D, frame_buffer->texture());
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
#endif
|
||||
}
|
||||
// second iteration; get frame and save file
|
||||
else {
|
||||
|
||||
// set reading PBO
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[0]);
|
||||
|
||||
// get pixels
|
||||
unsigned char* ptr = (unsigned char*) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
||||
if (NULL != ptr) {
|
||||
// prepare memory buffer0
|
||||
unsigned char * data = (unsigned char*) malloc(size_);
|
||||
// transfer frame to data
|
||||
memmove(data, ptr, size_);
|
||||
// save in separate thread
|
||||
std::thread(save_png, filename_, data, w, h, c).detach();
|
||||
}
|
||||
// unmap
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
|
||||
// ok done
|
||||
glDeleteBuffers(2, pbo_);
|
||||
|
||||
// recorded one frame
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
// unsigned char * data = (unsigned char*) malloc(size);
|
||||
// GLenum format = frame_buffer->use_alpha() ? GL_RGBA : GL_RGB;
|
||||
// glGetTextureSubImage( frame_buffer->texture(), 0, 0, 0, 0, w, h, 1, format, GL_UNSIGNED_BYTE, size, data);
|
||||
|
||||
}
|
||||
|
||||
const char* VideoRecorder::profile_name[VideoRecorder::DEFAULT] = {
|
||||
"H264 (Baseline)",
|
||||
"H264 (High 4:4:4)",
|
||||
"H265 (Realtime)",
|
||||
"H265 (HQ Animation)",
|
||||
"ProRes (Standard)",
|
||||
"ProRes (HQ 4444)",
|
||||
"WebM VP8 (2MB/s)",
|
||||
"Multiple JPEG"
|
||||
};
|
||||
const std::vector<std::string> VideoRecorder::profile_description {
|
||||
// Control x264 encoder quality :
|
||||
// pass
|
||||
// quant (4) – Constant Quantizer
|
||||
// qual (5) – Constant Quality
|
||||
// quantizer
|
||||
// The total range is from 0 to 51, where 0 is lossless, 18 can be considered ‘visually lossless’,
|
||||
// and 51 is terrible quality. A sane range is 18-26, and the default is 23.
|
||||
// speed-preset
|
||||
// veryfast (3)
|
||||
// faster (4)
|
||||
// fast (5)
|
||||
"x264enc pass=4 quantizer=23 speed-preset=3 threads=4 ! video/x-h264, profile=baseline ! h264parse ! ",
|
||||
"x264enc pass=4 quantizer=16 speed-preset=4 ! video/x-h264, profile=(string)high-4:4:4 ! h264parse ! ",
|
||||
// Control x265 encoder quality :
|
||||
// NB: apparently x265 only accepts I420 format :(
|
||||
// speed-preset
|
||||
// veryfast (3)
|
||||
// faster (4)
|
||||
// fast (5)
|
||||
// Tune
|
||||
// psnr (1)
|
||||
// ssim (2) DEFAULT
|
||||
// grain (3)
|
||||
// zerolatency (4) Encoder latency is removed
|
||||
// fastdecode (5)
|
||||
// animation (6) optimize the encode quality for animation content without impacting the encode speed
|
||||
// crf Quality-controlled variable bitrate [0 51]
|
||||
// default 28
|
||||
// 24 for x265 should be visually transparent; anything lower will probably just waste file size
|
||||
"video/x-raw, format=I420 ! x265enc tune=4 speed-preset=3 ! video/x-h265, profile=(string)main ! h265parse ! ",
|
||||
"video/x-raw, format=I420 ! x265enc tune=6 speed-preset=4 option-string=\"crf=22\" ! video/x-h265, profile=(string)main ! h265parse ! ",
|
||||
// Apple ProRes encoding parameters
|
||||
// pass
|
||||
// cbr (0) – Constant Bitrate Encoding
|
||||
// quant (2) – Constant Quantizer
|
||||
// pass1 (512) – VBR Encoding - Pass 1
|
||||
// profile
|
||||
// 0 ‘proxy’
|
||||
// 1 ‘lt’
|
||||
// 2 ‘standard’
|
||||
// 3 ‘hq’
|
||||
// 4 ‘4444’
|
||||
"avenc_prores_ks pass=2 profile=2 quantizer=26 ! ",
|
||||
"avenc_prores_ks pass=2 profile=4 quantizer=18 ! ",
|
||||
"vp8enc end-usage=vbr cpu-used=8 max-quantizer=35 deadline=100000 target-bitrate=200000 keyframe-max-dist=360 token-partitions=2 static-threshold=100 ! ",
|
||||
"jpegenc ! "
|
||||
};
|
||||
|
||||
// Too slow
|
||||
//// WebM VP9 encoding parameters
|
||||
//// https://www.webmproject.org/docs/encoder-parameters/
|
||||
//// https://developers.google.com/media/vp9/settings/vod/
|
||||
//"vp9enc end-usage=vbr end-usage=vbr cpu-used=3 max-quantizer=35 target-bitrate=200000 keyframe-max-dist=360 token-partitions=2 static-threshold=1000 ! "
|
||||
|
||||
// FAILED
|
||||
// x265 encoder quality
|
||||
// string description = "appsrc name=src ! videoconvert ! "
|
||||
// "x265enc tune=4 speed-preset=2 option-string='crf=28' ! h265parse ! "
|
||||
// "qtmux ! filesink name=sink";
|
||||
|
||||
|
||||
VideoRecorder::VideoRecorder() : Recorder(), frame_buffer_(nullptr), width_(0), height_(0),
|
||||
recording_(false), accept_buffer_(false), pipeline_(nullptr), src_(nullptr), timestamp_(0)
|
||||
{
|
||||
|
||||
// configure fix parameter
|
||||
frame_duration_ = gst_util_uint64_scale_int (1, GST_SECOND, 30); // 30 FPS
|
||||
timeframe_ = 2 * frame_duration_;
|
||||
}
|
||||
|
||||
VideoRecorder::~VideoRecorder()
|
||||
{
|
||||
if (src_ != nullptr)
|
||||
gst_object_unref (src_);
|
||||
if (pipeline_ != nullptr) {
|
||||
gst_element_set_state (pipeline_, GST_STATE_NULL);
|
||||
gst_object_unref (pipeline_);
|
||||
}
|
||||
|
||||
glDeleteBuffers(2, pbo_);
|
||||
}
|
||||
|
||||
void VideoRecorder::addFrame (FrameBuffer *frame_buffer, float dt)
|
||||
{
|
||||
// TODO : avoid software videoconvert by using a GPU shader to produce Y444 frames
|
||||
|
||||
// ignore
|
||||
if (frame_buffer == nullptr)
|
||||
return;
|
||||
|
||||
// first frame for initialization
|
||||
if (frame_buffer_ == nullptr) {
|
||||
|
||||
// set frame buffer as input
|
||||
frame_buffer_ = frame_buffer;
|
||||
|
||||
// define stream properties
|
||||
width_ = frame_buffer_->width();
|
||||
height_ = frame_buffer_->height();
|
||||
size_ = width_ * height_ * (frame_buffer_->use_alpha() ? 4 : 3);
|
||||
|
||||
// create PBOs
|
||||
glGenBuffers(2, pbo_);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[1]);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[0]);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ);
|
||||
|
||||
// create a gstreamer pipeline
|
||||
string description = "appsrc name=src ! videoconvert ! ";
|
||||
if (Settings::application.record.profile < 0 || Settings::application.record.profile >= DEFAULT)
|
||||
Settings::application.record.profile = H264_STANDARD;
|
||||
description += profile_description[Settings::application.record.profile];
|
||||
|
||||
// verify location path (path is always terminated by the OS dependent separator)
|
||||
std::string path = SystemToolkit::path_directory(Settings::application.record.path);
|
||||
if (path.empty())
|
||||
path = SystemToolkit::home_path();
|
||||
|
||||
// setup filename & muxer
|
||||
if( Settings::application.record.profile == JPEG_MULTI) {
|
||||
std::string folder = path + SystemToolkit::date_time_string() + "_vimix_jpg";
|
||||
filename_ = SystemToolkit::full_filename(folder, "%05d.jpg");
|
||||
if (SystemToolkit::create_directory(folder))
|
||||
description += "multifilesink name=sink";
|
||||
}
|
||||
else if( Settings::application.record.profile == VP8) {
|
||||
filename_ = path + SystemToolkit::date_time_string() + "_vimix.webm";
|
||||
description += "webmmux ! filesink name=sink";
|
||||
}
|
||||
else {
|
||||
filename_ = path + SystemToolkit::date_time_string() + "_vimix.mov";
|
||||
description += "qtmux ! filesink name=sink";
|
||||
}
|
||||
|
||||
// parse pipeline descriptor
|
||||
GError *error = NULL;
|
||||
pipeline_ = gst_parse_launch (description.c_str(), &error);
|
||||
if (error != NULL) {
|
||||
Log::Warning("VideoRecorder Could not construct pipeline %s:\n%s", description.c_str(), error->message);
|
||||
g_clear_error (&error);
|
||||
finished_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// setup file sink
|
||||
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
|
||||
"location", filename_.c_str(),
|
||||
"sync", FALSE,
|
||||
NULL);
|
||||
|
||||
// setup custom app source
|
||||
src_ = GST_APP_SRC( gst_bin_get_by_name (GST_BIN (pipeline_), "src") );
|
||||
if (src_) {
|
||||
|
||||
g_object_set (G_OBJECT (src_),
|
||||
"stream-type", GST_APP_STREAM_TYPE_STREAM,
|
||||
"is-live", TRUE,
|
||||
"format", GST_FORMAT_TIME,
|
||||
// "do-timestamp", TRUE,
|
||||
NULL);
|
||||
|
||||
// Direct encoding (no buffering)
|
||||
gst_app_src_set_max_bytes( src_, 0 );
|
||||
// gst_app_src_set_max_bytes( src_, 2 * buf_size_);
|
||||
|
||||
// instruct src to use the required caps
|
||||
GstCaps *caps = gst_caps_new_simple ("video/x-raw",
|
||||
"format", G_TYPE_STRING, frame_buffer_->use_alpha() ? "RGBA" : "RGB",
|
||||
"width", G_TYPE_INT, width_,
|
||||
"height", G_TYPE_INT, height_,
|
||||
"framerate", GST_TYPE_FRACTION, 30, 1,
|
||||
NULL);
|
||||
gst_app_src_set_caps (src_, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
// setup callbacks
|
||||
GstAppSrcCallbacks callbacks;
|
||||
callbacks.need_data = callback_need_data;
|
||||
callbacks.enough_data = callback_enough_data;
|
||||
callbacks.seek_data = NULL; // stream type is not seekable
|
||||
gst_app_src_set_callbacks (src_, &callbacks, this, NULL);
|
||||
|
||||
}
|
||||
else {
|
||||
Log::Warning("VideoRecorder Could not configure capture source");
|
||||
finished_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// start recording
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_PLAYING);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||
Log::Warning("VideoRecorder Could not record %s", filename_.c_str());
|
||||
finished_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// all good
|
||||
Log::Info("VideoRecorder start recording (%s %d x %d)", profile_name[Settings::application.record.profile], width_, height_);
|
||||
|
||||
// start recording !!
|
||||
recording_ = true;
|
||||
}
|
||||
// frame buffer changed ?
|
||||
else if (frame_buffer_ != frame_buffer) {
|
||||
|
||||
// if an incompatilble frame buffer given: stop recorder
|
||||
if ( frame_buffer->width() != width_ ||
|
||||
frame_buffer->height() != height_ ||
|
||||
frame_buffer->use_alpha() != frame_buffer_->use_alpha()) {
|
||||
|
||||
stop();
|
||||
Log::Warning("Recording interrupted: new session (%d x %d) incompatible with recording (%d x %d)", frame_buffer->width(), frame_buffer->height(), width_, height_);
|
||||
}
|
||||
else {
|
||||
// accepting a new frame buffer as input
|
||||
frame_buffer_ = frame_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
// store a frame if recording is active
|
||||
if (recording_ && size_ > 0)
|
||||
{
|
||||
// calculate dt in ns
|
||||
timeframe_ += gst_gdouble_to_guint64( dt * 1000000.f);
|
||||
|
||||
// if time is passed one frame duration (with 10% margin)
|
||||
// and if the encoder accepts data
|
||||
if ( timeframe_ > frame_duration_ - 3000000 && accept_buffer_) {
|
||||
|
||||
// set buffer target for writing in a new frame
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[pbo_index_]);
|
||||
|
||||
#ifdef USE_GLREADPIXEL
|
||||
// get frame
|
||||
frame_buffer->readPixels();
|
||||
#else
|
||||
glBindTexture(GL_TEXTURE_2D, frame_buffer->texture());
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
#endif
|
||||
|
||||
// update case ; alternating indices
|
||||
if ( pbo_next_index_ != pbo_index_ ) {
|
||||
|
||||
// set buffer target for saving the frame
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_[pbo_next_index_]);
|
||||
|
||||
// new buffer
|
||||
GstBuffer *buffer = gst_buffer_new_and_alloc (size_);
|
||||
|
||||
// set timing of buffer
|
||||
buffer->pts = timestamp_;
|
||||
buffer->duration = frame_duration_;
|
||||
|
||||
// map gst buffer into a memory WRITE target
|
||||
GstMapInfo map;
|
||||
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
|
||||
|
||||
// map PBO pixels into a memory READ pointer
|
||||
unsigned char* ptr = (unsigned char*) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
||||
|
||||
// transfer pixels from PBO memory to buffer memory
|
||||
if (NULL != ptr)
|
||||
memmove(map.data, ptr, size_);
|
||||
|
||||
// un-map
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
// push
|
||||
// Log::Info("VideoRecorder push data %ld", buffer->pts);
|
||||
gst_app_src_push_buffer (src_, buffer);
|
||||
// NB: buffer will be unrefed by the appsrc
|
||||
|
||||
// next timestamp
|
||||
timestamp_ += frame_duration_;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
// alternate indices
|
||||
pbo_next_index_ = pbo_index_;
|
||||
pbo_index_ = (pbo_index_ + 1) % 2;
|
||||
|
||||
// restart frame counter
|
||||
timeframe_ = 0;
|
||||
}
|
||||
|
||||
}
|
||||
// did the recording terminate with sink receiving end-of-stream ?
|
||||
else
|
||||
{
|
||||
// Wait for EOS message
|
||||
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
|
||||
GstMessage *msg = gst_bus_poll(bus, GST_MESSAGE_EOS, GST_TIME_AS_USECONDS(1));
|
||||
|
||||
if (msg) {
|
||||
// Log::Info("received EOS");
|
||||
// stop the pipeline
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_NULL);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
Log::Warning("VideoRecorder Could not stop");
|
||||
else
|
||||
Log::Notify("Recording %s ready.", filename_.c_str());
|
||||
|
||||
finished_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void VideoRecorder::stop ()
|
||||
{
|
||||
// send end of stream
|
||||
gst_app_src_end_of_stream (src_);
|
||||
// Log::Info("VideoRecorder push EOS");
|
||||
|
||||
// stop recording
|
||||
recording_ = false;
|
||||
}
|
||||
|
||||
std::string VideoRecorder::info()
|
||||
{
|
||||
if (recording_)
|
||||
return GstToolkit::time_to_string(timestamp_);
|
||||
else
|
||||
return "Saving file...";
|
||||
}
|
||||
|
||||
|
||||
double VideoRecorder::duration()
|
||||
{
|
||||
return gst_guint64_to_gdouble( GST_TIME_AS_MSECONDS(timestamp_) ) / 1000.0;
|
||||
}
|
||||
|
||||
// appsrc needs data and we should start sending
|
||||
void VideoRecorder::callback_need_data (GstAppSrc *, guint , gpointer p)
|
||||
{
|
||||
// Log::Info("H264Recording callback_need_data");
|
||||
VideoRecorder *rec = (VideoRecorder *)p;
|
||||
if (rec) {
|
||||
rec->accept_buffer_ = rec->recording_ ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
// appsrc has enough data and we can stop sending
|
||||
void VideoRecorder::callback_enough_data (GstAppSrc *, gpointer p)
|
||||
{
|
||||
// Log::Info("H264Recording callback_enough_data");
|
||||
VideoRecorder *rec = (VideoRecorder *)p;
|
||||
if (rec) {
|
||||
rec->accept_buffer_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
105
Recorder.h
@@ -1,105 +0,0 @@
|
||||
#ifndef RECORDER_H
|
||||
#define RECORDER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/app/gstappsrc.h>
|
||||
|
||||
class FrameBuffer;
|
||||
|
||||
/**
|
||||
* @brief The Recorder class defines the base class for all recorders
|
||||
* used to save images or videos from a frame buffer.
|
||||
*
|
||||
* The Mixer class calls addFrame() at each newly rendered frame for all of its recorder.
|
||||
*/
|
||||
class Recorder
|
||||
{
|
||||
public:
|
||||
Recorder();
|
||||
virtual ~Recorder() {}
|
||||
|
||||
virtual void addFrame(FrameBuffer *frame_buffer, float dt) = 0;
|
||||
virtual void stop() { }
|
||||
virtual std::string info() { return ""; }
|
||||
virtual double duration() { return 0.0; }
|
||||
|
||||
inline bool finished() const { return finished_; }
|
||||
|
||||
protected:
|
||||
// thread-safe testing termination
|
||||
std::atomic<bool> finished_;
|
||||
|
||||
// PBO
|
||||
guint pbo_[2];
|
||||
guint pbo_index_, pbo_next_index_;
|
||||
guint size_;
|
||||
};
|
||||
|
||||
class PNGRecorder : public Recorder
|
||||
{
|
||||
std::string filename_;
|
||||
|
||||
public:
|
||||
|
||||
PNGRecorder();
|
||||
void addFrame(FrameBuffer *frame_buffer, float) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class VideoRecorder : public Recorder
|
||||
{
|
||||
std::string filename_;
|
||||
|
||||
// Frame buffer information
|
||||
FrameBuffer *frame_buffer_;
|
||||
uint width_;
|
||||
uint height_;
|
||||
|
||||
// operation
|
||||
std::atomic<bool> recording_;
|
||||
std::atomic<bool> accept_buffer_;
|
||||
|
||||
// gstreamer pipeline
|
||||
GstElement *pipeline_;
|
||||
GstAppSrc *src_;
|
||||
GstClockTime timeframe_;
|
||||
GstClockTime timestamp_;
|
||||
GstClockTime frame_duration_;
|
||||
|
||||
static void callback_need_data (GstAppSrc *, guint, gpointer user_data);
|
||||
static void callback_enough_data (GstAppSrc *, gpointer user_data);
|
||||
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
H264_STANDARD = 0,
|
||||
H264_HQ,
|
||||
H265_REALTIME,
|
||||
H265_ANIMATION,
|
||||
PRORES_STANDARD,
|
||||
PRORES_HQ,
|
||||
VP8,
|
||||
JPEG_MULTI,
|
||||
DEFAULT
|
||||
} Profile;
|
||||
static const char* profile_name[DEFAULT];
|
||||
static const std::vector<std::string> profile_description;
|
||||
|
||||
VideoRecorder();
|
||||
~VideoRecorder();
|
||||
|
||||
void addFrame(FrameBuffer *frame_buffer, float dt) override;
|
||||
void stop() override;
|
||||
std::string info() override;
|
||||
|
||||
double duration() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // RECORDER_H
|
||||
@@ -1,827 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Desktop OpenGL function loader
|
||||
#include <glad/glad.h> // Initialized with gladLoadGLLoader()
|
||||
|
||||
// Include glfw3.h after our OpenGL definitions
|
||||
#define GLFW_INCLUDE_GLEXT
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifdef APPLE
|
||||
#include "osx/CocoaToolkit.h"
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#define GLFW_EXPOSE_NATIVE_NSGL
|
||||
#else
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#define GLFW_EXPOSE_NATIVE_GLX
|
||||
#endif
|
||||
#include <GLFW/glfw3native.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale
|
||||
#include <glm/ext/matrix_clip_space.hpp> // glm::perspective
|
||||
|
||||
// Include GStreamer
|
||||
#include <gst/gl/gl.h>
|
||||
#include <gst/gl/gstglcontext.h>
|
||||
|
||||
#ifdef GLFW_EXPOSE_NATIVE_COCOA
|
||||
#include <gst/gl/cocoa/gstgldisplay_cocoa.h>
|
||||
#endif
|
||||
#ifdef GLFW_EXPOSE_NATIVE_GLX
|
||||
#include <gst/gl/x11/gstgldisplay_x11.h>
|
||||
#endif
|
||||
|
||||
// standalone image loader
|
||||
#include <stb_image.h>
|
||||
|
||||
// vmix
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "Resource.h"
|
||||
#include "Settings.h"
|
||||
#include "Primitives.h"
|
||||
#include "Mixer.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "RenderingManager.h"
|
||||
|
||||
// local statics
|
||||
static GstGLContext *global_gl_context = NULL;
|
||||
static GstGLDisplay *global_display = NULL;
|
||||
|
||||
static std::map<GLFWwindow *, RenderingWindow*> GLFW_window_;
|
||||
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
Log::Error("Glfw Error %d: %s", error, description);
|
||||
}
|
||||
|
||||
static void WindowRefreshCallback( GLFWwindow * )
|
||||
{
|
||||
Rendering::manager().draw();
|
||||
}
|
||||
|
||||
static void WindowResizeCallback( GLFWwindow *w, int width, int height)
|
||||
{
|
||||
int id = GLFW_window_[w]->id();
|
||||
if (!Settings::application.windows[id].fullscreen) {
|
||||
Settings::application.windows[id].w = width;
|
||||
Settings::application.windows[id].h = height;
|
||||
}
|
||||
}
|
||||
|
||||
static void WindowMoveCallback( GLFWwindow *w, int x, int y)
|
||||
{
|
||||
int id = GLFW_window_[w]->id();
|
||||
if (!Settings::application.windows[id].fullscreen) {
|
||||
Settings::application.windows[id].x = x;
|
||||
Settings::application.windows[id].y = y;
|
||||
}
|
||||
}
|
||||
|
||||
static void WindowEscapeFullscreen( GLFWwindow *w, int key, int scancode, int action, int)
|
||||
{
|
||||
if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE)
|
||||
{
|
||||
// escape fullscreen
|
||||
GLFW_window_[w]->setFullscreen(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void WindowToggleFullscreen( GLFWwindow *w, int button, int action, int)
|
||||
{
|
||||
static double seconds = 0.f;
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
|
||||
{
|
||||
// detect double clic
|
||||
if ( glfwGetTime() - seconds < 0.2f ) {
|
||||
// toggle fullscreen
|
||||
GLFW_window_[w]->toggleFullscreen();
|
||||
}
|
||||
// for next clic detection
|
||||
seconds = glfwGetTime();
|
||||
}
|
||||
}
|
||||
|
||||
Rendering::Rendering()
|
||||
{
|
||||
// main_window_ = nullptr;
|
||||
request_screenshot_ = false;
|
||||
}
|
||||
|
||||
bool Rendering::init()
|
||||
{
|
||||
// Setup window
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
if (!glfwInit()){
|
||||
Log::Error("Failed to Initialize GLFW.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decide GL+GLSL versions GL 3.3 + GLSL 150
|
||||
glsl_version = "#version 150";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
#if __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||
#endif
|
||||
|
||||
//
|
||||
// OpenGL Multisampling main window
|
||||
//
|
||||
glfwWindowHint(GLFW_SAMPLES, Settings::application.render.multisampling);
|
||||
main_.init(0);
|
||||
// set application icon
|
||||
main_.setIcon("images/vimix_256x256.png");
|
||||
// additional window callbacks for main window
|
||||
glfwSetWindowRefreshCallback( main_.window(), WindowRefreshCallback );
|
||||
glfwSetDropCallback( main_.window(), Rendering::FileDropped);
|
||||
|
||||
//
|
||||
// Gstreamer setup
|
||||
//
|
||||
std::string plugins_path = SystemToolkit::cwd_path() + "gstreamer-1.0";
|
||||
std::string plugins_scanner = SystemToolkit::cwd_path() + "gst-plugin-scanner" ;
|
||||
if ( SystemToolkit::file_exists(plugins_path)) {
|
||||
Log::Info("Found Gstreamer plugins in %s", plugins_path.c_str());
|
||||
g_setenv ("GST_PLUGIN_SYSTEM_PATH", plugins_path.c_str(), TRUE);
|
||||
g_setenv ("GST_PLUGIN_SCANNER", plugins_scanner.c_str(), TRUE);
|
||||
}
|
||||
g_setenv ("GST_GL_API", "opengl3", TRUE);
|
||||
gst_init (NULL, NULL);
|
||||
|
||||
|
||||
//#if GST_GL_HAVE_PLATFORM_WGL
|
||||
// global_gl_context = gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (),
|
||||
// GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
|
||||
//#elif GST_GL_HAVE_PLATFORM_CGL
|
||||
//// global_display = GST_GL_DISPLAY ( glfwGetCocoaMonitor(main_.window()) );
|
||||
// global_display = GST_GL_DISPLAY (gst_gl_display_cocoa_new ());
|
||||
|
||||
// global_gl_context = gst_gl_context_new_wrapped (global_display,
|
||||
// (guintptr) 0,
|
||||
// GST_GL_PLATFORM_CGL, GST_GL_API_OPENGL);
|
||||
//#elif GST_GL_HAVE_PLATFORM_GLX
|
||||
// global_display = (GstGLDisplay*) gst_gl_display_x11_new_with_display( glfwGetX11Display() );
|
||||
// global_gl_context = gst_gl_context_new_wrapped (global_display,
|
||||
// (guintptr) glfwGetGLXContext(main_.window()),
|
||||
// GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
|
||||
//#endif
|
||||
|
||||
|
||||
//
|
||||
// output window
|
||||
//
|
||||
glfwWindowHint(GLFW_SAMPLES, 0); // no need for multisampling in displaying output
|
||||
output_.init(1, main_.window());
|
||||
output_.setIcon("images/vimix_256x256.png");
|
||||
// special callbacks for user input in output window
|
||||
glfwSetKeyCallback( output_.window(), WindowEscapeFullscreen);
|
||||
glfwSetMouseButtonCallback( output_.window(), WindowToggleFullscreen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Rendering::show()
|
||||
{
|
||||
// show output window
|
||||
output_.show();
|
||||
|
||||
// show main window
|
||||
main_.show();
|
||||
|
||||
// show menu on first show
|
||||
UserInterface::manager().showPannel(NAV_MENU);
|
||||
}
|
||||
|
||||
bool Rendering::isActive()
|
||||
{
|
||||
return !glfwWindowShouldClose(main_.window());
|
||||
}
|
||||
|
||||
|
||||
void Rendering::pushFrontDrawCallback(RenderingCallback function)
|
||||
{
|
||||
draw_callbacks_.push_front(function);
|
||||
}
|
||||
|
||||
void Rendering::pushBackDrawCallback(RenderingCallback function)
|
||||
{
|
||||
draw_callbacks_.push_back(function);
|
||||
}
|
||||
|
||||
void Rendering::draw()
|
||||
{
|
||||
|
||||
// operate on main window context
|
||||
main_.makeCurrent();
|
||||
|
||||
// User Interface step 1
|
||||
UserInterface::manager().NewFrame();
|
||||
|
||||
// Custom draw
|
||||
std::list<Rendering::RenderingCallback>::iterator iter;
|
||||
for (iter=draw_callbacks_.begin(); iter != draw_callbacks_.end(); iter++)
|
||||
{
|
||||
(*iter)();
|
||||
}
|
||||
|
||||
// User Interface step 2
|
||||
UserInterface::manager().Render();
|
||||
|
||||
// perform screenshot if requested
|
||||
if (request_screenshot_) {
|
||||
// glfwMakeContextCurrent(main_window_);
|
||||
screenshot_.captureGL(0, 0, main_.width(), main_.height());
|
||||
request_screenshot_ = false;
|
||||
}
|
||||
|
||||
// draw output window (and swap buffer output)
|
||||
output_.draw( Mixer::manager().session()->frame() );
|
||||
|
||||
// swap GL buffers
|
||||
glfwSwapBuffers(main_.window());
|
||||
glfwSwapBuffers(output_.window());
|
||||
|
||||
// Poll and handle events (inputs, window resize, etc.)
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
glfwPollEvents();
|
||||
|
||||
// no g_main_loop_run(loop) : update global GMainContext
|
||||
g_main_context_iteration(NULL, FALSE);
|
||||
}
|
||||
|
||||
|
||||
void Rendering::terminate()
|
||||
{
|
||||
// close window
|
||||
glfwDestroyWindow(output_.window());
|
||||
glfwDestroyWindow(main_.window());
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
|
||||
void Rendering::close()
|
||||
{
|
||||
glfwSetWindowShouldClose(main_.window(), true);
|
||||
}
|
||||
|
||||
|
||||
void Rendering::pushAttrib(RenderingAttrib ra)
|
||||
{
|
||||
// push it to top of pile
|
||||
draw_attributes_.push_front(ra);
|
||||
|
||||
// apply Changes to OpenGL
|
||||
glViewport(0, 0, ra.viewport.x, ra.viewport.y);
|
||||
glClearColor(ra.clear_color.r, ra.clear_color.g, ra.clear_color.b, ra.clear_color.a);
|
||||
}
|
||||
|
||||
void Rendering::popAttrib()
|
||||
{
|
||||
// pops the top of the pile
|
||||
if (draw_attributes_.size() > 0)
|
||||
draw_attributes_.pop_front();
|
||||
|
||||
// set attribute element to default
|
||||
RenderingAttrib ra = currentAttrib();
|
||||
|
||||
// apply Changes to OpenGL
|
||||
glViewport(0, 0, ra.viewport.x, ra.viewport.y);
|
||||
glClearColor(ra.clear_color.r, ra.clear_color.g, ra.clear_color.b, ra.clear_color.a);
|
||||
}
|
||||
|
||||
RenderingAttrib Rendering::currentAttrib()
|
||||
{
|
||||
// default rendering attrib is the main window's
|
||||
RenderingAttrib ra = main_.attribs();
|
||||
|
||||
// but if there is an element at top, return it
|
||||
if (draw_attributes_.size() > 0)
|
||||
ra = draw_attributes_.front();
|
||||
return ra;
|
||||
}
|
||||
|
||||
glm::mat4 Rendering::Projection()
|
||||
{
|
||||
static glm::mat4 projection = glm::ortho(-SCENE_UNIT, SCENE_UNIT, -SCENE_UNIT, SCENE_UNIT, -SCENE_DEPTH, 1.f);
|
||||
glm::mat4 scale = glm::scale(glm::identity<glm::mat4>(), glm::vec3(1.f, main_.aspectRatio(), 1.f));
|
||||
|
||||
return projection * scale;
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 Rendering::unProject(glm::vec2 screen_coordinate, glm::mat4 modelview)
|
||||
{
|
||||
glm::vec3 coordinates = glm::vec3( screen_coordinate.x, main_.height() - screen_coordinate.y, 0.f);
|
||||
glm::vec4 viewport = glm::vec4( 0.f, 0.f, main_.width(), main_.height());
|
||||
|
||||
// Log::Info("unproject %d x %d", main_window_attributes_.viewport.x, main_window_attributes_.viewport.y);
|
||||
|
||||
glm::vec3 point = glm::unProject(coordinates, modelview, Projection(), viewport);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
glm::vec2 Rendering::project(glm::vec3 scene_coordinate, glm::mat4 modelview, bool to_framebuffer)
|
||||
{
|
||||
glm::vec4 viewport;
|
||||
if (to_framebuffer)
|
||||
viewport= glm::vec4( 0.f, 0.f, main_.width(), main_.height());
|
||||
else
|
||||
viewport= glm::vec4( 0.f, 0.f, main_.width() / main_.dpiScale(), main_.height() / main_.dpiScale());
|
||||
glm::vec3 P = glm::project( scene_coordinate, modelview, Projection(), viewport );
|
||||
|
||||
return glm::vec2(P.x, viewport.w - P.y);
|
||||
}
|
||||
|
||||
void Rendering::FileDropped(GLFWwindow *, int path_count, const char* paths[])
|
||||
{
|
||||
for (int i = 0; i < path_count; ++i) {
|
||||
std::string filename(paths[i]);
|
||||
if (filename.empty())
|
||||
break;
|
||||
// try to create a source
|
||||
Mixer::manager().addSource ( Mixer::manager().createSourceFile( filename ) );
|
||||
}
|
||||
if (path_count>0) {
|
||||
UserInterface::manager().showPannel();
|
||||
Rendering::manager().mainWindow().show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Screenshot *Rendering::currentScreenshot()
|
||||
{
|
||||
return &screenshot_;
|
||||
}
|
||||
|
||||
void Rendering::requestScreenshot()
|
||||
{
|
||||
request_screenshot_ = true;
|
||||
}
|
||||
|
||||
|
||||
// custom surface with a new VAO
|
||||
class WindowSurface : public Primitive {
|
||||
|
||||
public:
|
||||
WindowSurface(Shader *s = new ImageShader);
|
||||
};
|
||||
|
||||
WindowSurface::WindowSurface(Shader *s) : Primitive(s)
|
||||
{
|
||||
points_ = std::vector<glm::vec3> { glm::vec3( -1.f, -1.f, 0.f ), glm::vec3( -1.f, 1.f, 0.f ),
|
||||
glm::vec3( 1.f, -1.f, 0.f ), glm::vec3( 1.f, 1.f, 0.f ) };
|
||||
colors_ = std::vector<glm::vec4> { glm::vec4( 1.f, 1.f, 1.f , 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ),
|
||||
glm::vec4( 1.f, 1.f, 1.f, 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ) };
|
||||
texCoords_ = std::vector<glm::vec2> { glm::vec2( 0.f, 1.f ), glm::vec2( 0.f, 0.f ),
|
||||
glm::vec2( 1.f, 1.f ), glm::vec2( 1.f, 0.f ) };
|
||||
indices_ = std::vector<uint> { 0, 1, 2, 3 };
|
||||
drawMode_ = GL_TRIANGLE_STRIP;
|
||||
}
|
||||
|
||||
|
||||
RenderingWindow::RenderingWindow() : window_(nullptr), master_(nullptr),
|
||||
id_(-1), dpi_scale_(1.f), textureid_(0), fbo_(0), surface_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
RenderingWindow::~RenderingWindow()
|
||||
{
|
||||
if (surface_ != nullptr)
|
||||
delete surface_;
|
||||
if (fbo_ != 0)
|
||||
glDeleteFramebuffers(1, &fbo_);
|
||||
}
|
||||
|
||||
void RenderingWindow::setTitle(const std::string &title)
|
||||
{
|
||||
std::string fulltitle = Settings::application.windows[id_].name;
|
||||
if ( !title.empty() )
|
||||
fulltitle += " -- " + title;
|
||||
|
||||
glfwSetWindowTitle(window_, fulltitle.c_str());
|
||||
}
|
||||
|
||||
void RenderingWindow::setIcon(const std::string &resource)
|
||||
{
|
||||
size_t fpsize = 0;
|
||||
const char *fp = Resource::getData(resource, &fpsize);
|
||||
if (fp != nullptr) {
|
||||
GLFWimage icon;
|
||||
icon.pixels = stbi_load_from_memory( (const stbi_uc*)fp, fpsize, &icon.width, &icon.height, nullptr, 4 );
|
||||
glfwSetWindowIcon( window_, 1, &icon );
|
||||
free( icon.pixels );
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderingWindow::isFullscreen ()
|
||||
{
|
||||
return (glfwGetWindowMonitor(window_) != nullptr);
|
||||
// return Settings::application.windows[id_].fullscreen;
|
||||
}
|
||||
|
||||
GLFWmonitor *RenderingWindow::monitorAt(int x, int y)
|
||||
{
|
||||
// default to primary monitor
|
||||
GLFWmonitor *mo = glfwGetPrimaryMonitor();
|
||||
|
||||
// list all monitors
|
||||
int count_monitors = 0;
|
||||
GLFWmonitor** monitors = glfwGetMonitors(&count_monitors);
|
||||
// if there is more than one monitor
|
||||
if (count_monitors > 1) {
|
||||
// pick at the coordinates given or at pos of window
|
||||
// try every monitor
|
||||
int i = 0;
|
||||
for (; i < count_monitors; i++) {
|
||||
int workarea_x, workarea_y, workarea_width, workarea_height;
|
||||
glfwGetMonitorWorkarea(monitors[i], &workarea_x, &workarea_y, &workarea_width, &workarea_height);
|
||||
if ( x >= workarea_x && x <= workarea_x + workarea_width &&
|
||||
y >= workarea_y && y <= workarea_y + workarea_height)
|
||||
break;
|
||||
}
|
||||
// found the monitor containing this point !
|
||||
if ( i < count_monitors)
|
||||
mo = monitors[i];
|
||||
}
|
||||
|
||||
return mo;
|
||||
}
|
||||
|
||||
GLFWmonitor *RenderingWindow::monitorNamed(const std::string &name)
|
||||
{
|
||||
// default to primary monitor
|
||||
GLFWmonitor *mo = glfwGetPrimaryMonitor();
|
||||
|
||||
// list all monitors
|
||||
int count_monitors = 0;
|
||||
GLFWmonitor** monitors = glfwGetMonitors(&count_monitors);
|
||||
// if there is more than one monitor
|
||||
if (count_monitors > 1) {
|
||||
// pick at the coordinates given or at pos of window
|
||||
// try every monitor
|
||||
int i = 0;
|
||||
for (; i < count_monitors; i++) {
|
||||
if ( std::string( glfwGetMonitorName(monitors[i])) == name )
|
||||
break;
|
||||
}
|
||||
// found the monitor with this name
|
||||
if ( i < count_monitors)
|
||||
mo = monitors[i];
|
||||
}
|
||||
|
||||
return mo;
|
||||
}
|
||||
|
||||
GLFWmonitor *RenderingWindow::monitor()
|
||||
{
|
||||
// pick at the coordinates given or at pos of window
|
||||
int x, y;
|
||||
glfwGetWindowPos(window_, &x, &y);
|
||||
|
||||
return monitorAt(x, y);
|
||||
}
|
||||
|
||||
void RenderingWindow::setFullscreen(GLFWmonitor *mo)
|
||||
{
|
||||
// if in fullscreen mode
|
||||
if (mo == nullptr) {
|
||||
// set to window mode
|
||||
glfwSetInputMode( window_, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
glfwSetWindowMonitor( window_, nullptr, Settings::application.windows[id_].x,
|
||||
Settings::application.windows[id_].y,
|
||||
Settings::application.windows[id_].w,
|
||||
Settings::application.windows[id_].h, 0 );
|
||||
Settings::application.windows[id_].fullscreen = false;
|
||||
}
|
||||
// not in fullscreen mode
|
||||
else {
|
||||
// set to fullscreen mode
|
||||
Settings::application.windows[id_].fullscreen = true;
|
||||
Settings::application.windows[id_].monitor = glfwGetMonitorName(mo);
|
||||
|
||||
const GLFWvidmode * mode = glfwGetVideoMode(mo);
|
||||
glfwSetWindowMonitor( window_, mo, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||
glfwSetInputMode( window_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingWindow::toggleFullscreen()
|
||||
{
|
||||
// if in fullscreen mode
|
||||
if (isFullscreen()) {
|
||||
// exit fullscreen
|
||||
setFullscreen(nullptr);
|
||||
}
|
||||
// not in fullscreen mode
|
||||
else {
|
||||
// enter fullscreen in monitor where the window is
|
||||
setFullscreen(monitor());
|
||||
}
|
||||
}
|
||||
|
||||
int RenderingWindow::width()
|
||||
{
|
||||
return window_attributes_.viewport.x;
|
||||
}
|
||||
|
||||
int RenderingWindow::height()
|
||||
{
|
||||
return window_attributes_.viewport.y;
|
||||
}
|
||||
|
||||
int RenderingWindow::maxHeight()
|
||||
{
|
||||
int workarea_x, workarea_y, workarea_width, workarea_height;
|
||||
glfwGetMonitorWorkarea(monitor(), &workarea_x, &workarea_y, &workarea_width, &workarea_height);
|
||||
|
||||
return workarea_height * dpi_scale_;
|
||||
}
|
||||
|
||||
float RenderingWindow::aspectRatio()
|
||||
{
|
||||
return static_cast<float>(window_attributes_.viewport.x) / static_cast<float>(window_attributes_.viewport.y);
|
||||
}
|
||||
|
||||
bool RenderingWindow::init(int id, GLFWwindow *share)
|
||||
{
|
||||
id_ = id;
|
||||
master_ = share;
|
||||
|
||||
// access Settings
|
||||
Settings::WindowConfig winset = Settings::application.windows[id_];
|
||||
|
||||
// do not show at creation
|
||||
glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
|
||||
|
||||
// create the window normal
|
||||
window_ = glfwCreateWindow(winset.w, winset.h, winset.name.c_str(), NULL, master_);
|
||||
if (window_ == NULL){
|
||||
Log::Error("Failed to create GLFW Window %d", id_);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set position
|
||||
glfwSetWindowPos(window_, winset.x, winset.y);
|
||||
|
||||
/// CALLBACKS
|
||||
// store global ref to pointers (used by callbacks)
|
||||
GLFW_window_[window_] = this;
|
||||
// window position and resize callbacks
|
||||
glfwSetWindowSizeCallback( window_, WindowResizeCallback );
|
||||
// glfwSetFramebufferSizeCallback( window_, WindowResizeCallback );
|
||||
glfwSetWindowPosCallback( window_, WindowMoveCallback );
|
||||
|
||||
// take opengl context ownership
|
||||
glfwMakeContextCurrent(window_);
|
||||
|
||||
//
|
||||
// Initialize OpenGL loader on first call
|
||||
//
|
||||
static bool glad_initialized = false;
|
||||
if ( !glad_initialized ) {
|
||||
bool err = gladLoadGLLoader((GLADloadproc) glfwGetProcAddress) == 0;
|
||||
if (err) {
|
||||
Log::Error("Failed to initialize GLAD OpenGL loader.");
|
||||
return false;
|
||||
}
|
||||
glad_initialized = true;
|
||||
}
|
||||
|
||||
// get rendering area
|
||||
glfwGetFramebufferSize(window_, &(window_attributes_.viewport.x), &(window_attributes_.viewport.y));
|
||||
// DPI scaling (retina)
|
||||
dpi_scale_ = float(window_attributes_.viewport.y) / float(winset.h);
|
||||
|
||||
// This hint can improve the speed of texturing when perspective-correct texture coordinate interpolation isn't needed
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||
//
|
||||
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
|
||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||
|
||||
// if not main window
|
||||
if ( master_ != NULL ) {
|
||||
// Enable vsync on output window
|
||||
glfwSwapInterval(Settings::application.render.vsync);
|
||||
// no need for multisampling
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
// clear to black
|
||||
window_attributes_.clear_color = glm::vec4(0.f, 0.f, 0.f, 1.f);
|
||||
// give back context ownership
|
||||
glfwMakeContextCurrent(master_);
|
||||
}
|
||||
else {
|
||||
// Disable vsync on main window
|
||||
glfwSwapInterval(0);
|
||||
// Enable Antialiasing multisampling
|
||||
if (Settings::application.render.multisampling > 0) {
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
|
||||
}
|
||||
// clear to grey
|
||||
window_attributes_.clear_color = glm::vec4(COLOR_BGROUND, 1.f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderingWindow::show()
|
||||
{
|
||||
glfwShowWindow(window_);
|
||||
|
||||
if ( Settings::application.windows[id_].fullscreen ) {
|
||||
GLFWmonitor *mo = monitorNamed(Settings::application.windows[id_].monitor);
|
||||
setFullscreen(mo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RenderingWindow::makeCurrent()
|
||||
{
|
||||
// handle window resize
|
||||
glfwGetFramebufferSize(window_, &(window_attributes_.viewport.x), &(window_attributes_.viewport.y));
|
||||
|
||||
// ensure main context is current
|
||||
glfwMakeContextCurrent(window_);
|
||||
|
||||
// set and clear
|
||||
glViewport(0, 0, window_attributes_.viewport.x, window_attributes_.viewport.y);
|
||||
glClearColor(window_attributes_.clear_color.r, window_attributes_.clear_color.g,
|
||||
window_attributes_.clear_color.b, window_attributes_.clear_color.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// TODO update parameters for draw on resize event (not every frame)
|
||||
|
||||
void RenderingWindow::draw(FrameBuffer *fb)
|
||||
{
|
||||
if (!window_ || !fb)
|
||||
return;
|
||||
|
||||
// only draw if window is not iconified
|
||||
if( !glfwGetWindowAttrib(window_, GLFW_ICONIFIED ) ) {
|
||||
|
||||
// update viewport (could be done with callback)
|
||||
glfwGetFramebufferSize(window_, &(window_attributes_.viewport.x), &(window_attributes_.viewport.y));
|
||||
|
||||
// take context ownership
|
||||
glfwMakeContextCurrent(window_);
|
||||
|
||||
// setup attribs
|
||||
Rendering::manager().pushAttrib(window_attributes_);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// blit framebuffer
|
||||
if (Settings::application.render.blit) {
|
||||
|
||||
if ( textureid_ != fb->texture()) {
|
||||
|
||||
textureid_ = fb->texture();
|
||||
|
||||
// create a new fbo in this opengl context
|
||||
if (fbo_ != 0)
|
||||
glDeleteFramebuffers(1, &fbo_);
|
||||
glGenFramebuffers(1, &fbo_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
|
||||
// attach the 2D texture to local FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
|
||||
Log::Info("Blit to output window enabled.");
|
||||
}
|
||||
|
||||
// calculate scaling factor of frame buffer inside window
|
||||
int rx, ry, rw, rh;
|
||||
float renderingAspectRatio = fb->aspectRatio();
|
||||
if (aspectRatio() < renderingAspectRatio) {
|
||||
int nh = (int)( float(window_attributes_.viewport.x) / renderingAspectRatio);
|
||||
rx = 0;
|
||||
ry = (window_attributes_.viewport.y - nh) / 2;
|
||||
rw = window_attributes_.viewport.x;
|
||||
rh = (window_attributes_.viewport.y + nh) / 2;
|
||||
} else {
|
||||
int nw = (int)( float(window_attributes_.viewport.y) * renderingAspectRatio );
|
||||
rx = (window_attributes_.viewport.x - nw) / 2;
|
||||
ry = 0;
|
||||
rw = (window_attributes_.viewport.x + nw) / 2;
|
||||
rh = window_attributes_.viewport.y;
|
||||
}
|
||||
|
||||
// select fbo texture read target
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_);
|
||||
|
||||
// select screen target
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
// blit operation from fbo (containing texture) to screen
|
||||
glBlitFramebuffer(0, fb->height(), fb->width(), 0, rx, ry, rw, rh, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
}
|
||||
// draw geometry
|
||||
else
|
||||
{
|
||||
// VAO is not shared between multiple contexts of different windows
|
||||
// so we have to create a new VAO for rendering the surface in this window
|
||||
if (surface_ == 0)
|
||||
surface_ = new WindowSurface;
|
||||
|
||||
// calculate scaling factor of frame buffer inside window
|
||||
float windowAspectRatio = aspectRatio();
|
||||
float renderingAspectRatio = fb->aspectRatio();
|
||||
glm::vec3 scale;
|
||||
if (windowAspectRatio < renderingAspectRatio)
|
||||
scale = glm::vec3(1.f, windowAspectRatio / renderingAspectRatio, 1.f);
|
||||
else
|
||||
scale = glm::vec3(renderingAspectRatio / windowAspectRatio, 1.f, 1.f);
|
||||
|
||||
// make sure previous shader in another glcontext is disabled
|
||||
ShadingProgram::enduse();
|
||||
|
||||
// draw
|
||||
glBindTexture(GL_TEXTURE_2D, fb->texture());
|
||||
// surface->shader()->color.a = 0.4f; // TODO alpha blending ?
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
|
||||
surface_->draw(glm::scale(glm::identity<glm::mat4>(), scale), projection);
|
||||
|
||||
// done drawing (unload shader from this glcontext)
|
||||
ShadingProgram::enduse();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
// restore attribs
|
||||
Rendering::manager().popAttrib();
|
||||
|
||||
}
|
||||
|
||||
// give back context ownership
|
||||
glfwMakeContextCurrent(master_);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Discarded because not working under OSX - kept in case it would become useful
|
||||
//
|
||||
// Linking pipeline to the rendering instance ensures the opengl contexts
|
||||
// created by gstreamer inside plugins (e.g. glsinkbin) is the same
|
||||
//
|
||||
|
||||
static GstBusSyncReply
|
||||
bus_sync_handler (GstBus *, GstMessage * msg, gpointer )
|
||||
{
|
||||
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT) {
|
||||
const gchar* contextType;
|
||||
gst_message_parse_context_type(msg, &contextType);
|
||||
|
||||
if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE)) {
|
||||
GstContext *displayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
|
||||
gst_context_set_gl_display(displayContext, global_display);
|
||||
gst_element_set_context(GST_ELEMENT(msg->src), displayContext);
|
||||
gst_context_unref (displayContext);
|
||||
|
||||
g_info ("Managed %s\n", contextType);
|
||||
}
|
||||
if (!g_strcmp0(contextType, "gst.gl.app_context")) {
|
||||
GstContext *appContext = gst_context_new("gst.gl.app_context", TRUE);
|
||||
GstStructure* structure = gst_context_writable_structure(appContext);
|
||||
gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, global_gl_context, nullptr);
|
||||
gst_element_set_context(GST_ELEMENT(msg->src), appContext);
|
||||
gst_context_unref (appContext);
|
||||
|
||||
g_info ("Managed %s\n", contextType);
|
||||
}
|
||||
}
|
||||
|
||||
gst_message_unref (msg);
|
||||
|
||||
return GST_BUS_DROP;
|
||||
}
|
||||
|
||||
void Rendering::LinkPipeline( GstPipeline *pipeline )
|
||||
{
|
||||
// capture bus signals to force a unique opengl context for all GST elements
|
||||
GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
gst_bus_set_sync_handler (m_bus, (GstBusSyncHandler) bus_sync_handler, pipeline, NULL);
|
||||
gst_object_unref (m_bus);
|
||||
|
||||
|
||||
// GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
// gst_bus_enable_sync_message_emission (m_bus);
|
||||
// g_signal_connect (m_bus, "sync-message", G_CALLBACK (bus_sync_handler), pipeline);
|
||||
// gst_object_unref (m_bus);
|
||||
}
|
||||
136
Screenshot.cpp
@@ -1,136 +0,0 @@
|
||||
#include "Screenshot.h"
|
||||
|
||||
#include <memory.h>
|
||||
#include <assert.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
// standalone image loader
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
|
||||
|
||||
Screenshot::Screenshot()
|
||||
{
|
||||
Width = Height = 0;
|
||||
Data = nullptr;
|
||||
Pbo = 0;
|
||||
Pbo_size = 0;
|
||||
Pbo_full = false;
|
||||
}
|
||||
|
||||
Screenshot::~Screenshot()
|
||||
{
|
||||
glDeleteBuffers(1, &Pbo);
|
||||
if (Data) free(Data);
|
||||
}
|
||||
|
||||
bool Screenshot::isFull()
|
||||
{
|
||||
return Pbo_full;
|
||||
}
|
||||
|
||||
void Screenshot::captureGL(int x, int y, int w, int h)
|
||||
{
|
||||
Width = w - x;
|
||||
Height = h - y;
|
||||
unsigned int size = Width * Height * 4;
|
||||
|
||||
// create BPO
|
||||
if (Pbo == 0)
|
||||
glGenBuffers(1, &Pbo);
|
||||
|
||||
// bind
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, Pbo);
|
||||
|
||||
// init
|
||||
if (Pbo_size != size) {
|
||||
Pbo_size = size;
|
||||
if (Data) free(Data);
|
||||
Data = (unsigned char*) malloc(Pbo_size);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, Pbo_size, NULL, GL_STREAM_READ);
|
||||
}
|
||||
|
||||
// screenshot to PBO (fast)
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
Pbo_full = true;
|
||||
|
||||
// done
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
void Screenshot::save(std::string filename)
|
||||
{
|
||||
// is there something to save?
|
||||
if (Pbo && Pbo_size > 0 && Pbo_full) {
|
||||
|
||||
// bind buffer
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, Pbo);
|
||||
|
||||
// get pixels (quite fast)
|
||||
unsigned char* ptr = (unsigned char*) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
||||
if (NULL != ptr) {
|
||||
memmove(Data, ptr, Pbo_size);
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
}
|
||||
|
||||
// initiate saving in thread (slow)
|
||||
std::thread(storeToFile, this, filename).detach();
|
||||
|
||||
// ready for next
|
||||
Pbo_full = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Screenshot::RemoveAlpha()
|
||||
{
|
||||
unsigned int* p = (unsigned int*)Data;
|
||||
int n = Width * Height;
|
||||
while (n-- > 0)
|
||||
{
|
||||
*p |= 0xFF000000;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
void Screenshot::FlipVertical()
|
||||
{
|
||||
int comp = 4;
|
||||
int stride = Width * comp;
|
||||
unsigned char* line_tmp = new unsigned char[stride];
|
||||
unsigned char* line_a = (unsigned char*)Data;
|
||||
unsigned char* line_b = (unsigned char*)Data + (stride * (Height - 1));
|
||||
while (line_a < line_b)
|
||||
{
|
||||
memcpy(line_tmp, line_a, stride);
|
||||
memcpy(line_a, line_b, stride);
|
||||
memcpy(line_b, line_tmp, stride);
|
||||
line_a += stride;
|
||||
line_b -= stride;
|
||||
}
|
||||
delete[] line_tmp;
|
||||
}
|
||||
|
||||
// Thread to perform slow operation of saving to file
|
||||
void Screenshot::storeToFile(Screenshot *s, std::string filename)
|
||||
{
|
||||
static std::atomic<bool> ScreenshotSavePending_ = false;
|
||||
// only one save at a time
|
||||
if (ScreenshotSavePending_)
|
||||
return;
|
||||
ScreenshotSavePending_ = true;
|
||||
// got data to save ?
|
||||
if (s && s->Data) {
|
||||
// make it usable
|
||||
s->RemoveAlpha();
|
||||
s->FlipVertical();
|
||||
// save file
|
||||
stbi_write_png(filename.c_str(), s->Width, s->Height, 4, s->Data, s->Width * 4);
|
||||
}
|
||||
ScreenshotSavePending_ = false;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#include "SearchVisitor.h"
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
SearchVisitor::SearchVisitor(Node *node) : Visitor(), node_(node), found_(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SearchVisitor::visit(Node &n)
|
||||
{
|
||||
if ( !found_ && node_ == &n ){
|
||||
found_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SearchVisitor::visit(Group &n)
|
||||
{
|
||||
if (found_)
|
||||
return;
|
||||
|
||||
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||
(*node)->accept(*this);
|
||||
if (found_)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SearchVisitor::visit(Switch &n)
|
||||
{
|
||||
if (n.numChildren()>0)
|
||||
n.activeChild()->accept(*this);
|
||||
}
|
||||
|
||||
|
||||
void SearchVisitor::visit(Scene &n)
|
||||
{
|
||||
// search only in workspace
|
||||
n.ws()->accept(*this);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef SEARCHVISITOR_H
|
||||
#define SEARCHVISITOR_H
|
||||
|
||||
#include "Visitor.h"
|
||||
|
||||
class SearchVisitor: public Visitor
|
||||
{
|
||||
Node *node_;
|
||||
bool found_;
|
||||
|
||||
public:
|
||||
SearchVisitor(Node *node);
|
||||
inline bool found() const { return found_; }
|
||||
inline Node *node() const { return found_ ? node_ : nullptr; }
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Scene& n);
|
||||
void visit(Node& n);
|
||||
void visit(Primitive&) {}
|
||||
void visit(Group& n);
|
||||
void visit(Switch& n);
|
||||
|
||||
};
|
||||
|
||||
#endif // SEARCHVISITOR_H
|
||||
274
Session.cpp
@@ -1,274 +0,0 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Settings.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Session.h"
|
||||
#include "GarbageVisitor.h"
|
||||
#include "Recorder.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
Session::Session() : filename_(""), failedSource_(nullptr), active_(true), fading_target_(0.f)
|
||||
{
|
||||
config_[View::RENDERING] = new Group;
|
||||
config_[View::RENDERING]->scale_ = render_.resolution();
|
||||
|
||||
config_[View::GEOMETRY] = new Group;
|
||||
config_[View::GEOMETRY]->scale_ = Settings::application.views[View::GEOMETRY].default_scale;
|
||||
config_[View::GEOMETRY]->translation_ = Settings::application.views[View::GEOMETRY].default_translation;
|
||||
|
||||
config_[View::LAYER] = new Group;
|
||||
config_[View::LAYER]->scale_ = Settings::application.views[View::LAYER].default_scale;
|
||||
config_[View::LAYER]->translation_ = Settings::application.views[View::LAYER].default_translation;
|
||||
|
||||
config_[View::MIXING] = new Group;
|
||||
config_[View::MIXING]->scale_ = Settings::application.views[View::MIXING].default_scale;
|
||||
config_[View::MIXING]->translation_ = Settings::application.views[View::MIXING].default_translation;
|
||||
}
|
||||
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
// delete all recorders
|
||||
clearRecorders();
|
||||
|
||||
// delete all sources
|
||||
for(auto it = sources_.begin(); it != sources_.end(); ) {
|
||||
// erase this source from the list
|
||||
it = deleteSource(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::setActive (bool on)
|
||||
{
|
||||
if (active_ != on) {
|
||||
active_ = on;
|
||||
for(auto it = sources_.begin(); it != sources_.end(); it++) {
|
||||
(*it)->setActive(active_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update all sources
|
||||
void Session::update(float dt)
|
||||
{
|
||||
failedSource_ = nullptr;
|
||||
|
||||
// pre-render of all sources
|
||||
for( SourceList::iterator it = sources_.begin(); it != sources_.end(); it++){
|
||||
|
||||
if ( (*it)->failed() ) {
|
||||
failedSource_ = (*it);
|
||||
}
|
||||
else {
|
||||
// render the source
|
||||
(*it)->render();
|
||||
// update the source
|
||||
(*it)->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
// apply fading (smooth dicotomic reaching)
|
||||
float f = render_.fading();
|
||||
if ( ABS_DIFF(f, fading_target_) > EPSILON) {
|
||||
render_.setFading( f + ( fading_target_ - f ) / 2.f);
|
||||
}
|
||||
|
||||
// update the scene tree
|
||||
render_.update(dt);
|
||||
|
||||
// draw render view in Frame Buffer
|
||||
render_.draw();
|
||||
|
||||
// send frame to recorders
|
||||
std::list<Recorder *>::iterator iter;
|
||||
for (iter=recorders_.begin(); iter != recorders_.end(); )
|
||||
{
|
||||
Recorder *rec = *iter;
|
||||
|
||||
rec->addFrame(render_.frame(), dt);
|
||||
|
||||
if (rec->finished()) {
|
||||
iter = recorders_.erase(iter);
|
||||
delete rec;
|
||||
}
|
||||
else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SourceList::iterator Session::addSource(Source *s)
|
||||
{
|
||||
// insert the source in the rendering
|
||||
render_.scene.ws()->attach(s->group(View::RENDERING));
|
||||
// insert the source to the beginning of the list
|
||||
sources_.push_front(s);
|
||||
// return the iterator to the source created at the beginning
|
||||
return sources_.begin();
|
||||
}
|
||||
|
||||
SourceList::iterator Session::deleteSource(Source *s)
|
||||
{
|
||||
// find the source
|
||||
SourceList::iterator its = find(s);
|
||||
// ok, its in the list !
|
||||
if (its != sources_.end()) {
|
||||
|
||||
// remove Node from the rendering scene
|
||||
render_.scene.ws()->detatch( s->group(View::RENDERING) );
|
||||
|
||||
// erase the source from the update list & get next element
|
||||
its = sources_.erase(its);
|
||||
|
||||
// delete the source : safe now
|
||||
delete s;
|
||||
}
|
||||
|
||||
// return end of next element
|
||||
return its;
|
||||
}
|
||||
|
||||
Source *Session::popSource()
|
||||
{
|
||||
Source *s = nullptr;
|
||||
|
||||
SourceList::iterator its = sources_.begin();
|
||||
if (its != sources_.end())
|
||||
{
|
||||
s = *its;
|
||||
|
||||
// remove Node from the rendering scene
|
||||
render_.scene.ws()->detatch( s->group(View::RENDERING) );
|
||||
|
||||
// erase the source from the update list & get next element
|
||||
sources_.erase(its);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void Session::setResolution(glm::vec3 resolution)
|
||||
{
|
||||
render_.setResolution(resolution);
|
||||
config_[View::RENDERING]->scale_ = resolution;
|
||||
}
|
||||
|
||||
void Session::setFading(float f, bool forcenow)
|
||||
{
|
||||
if (forcenow)
|
||||
render_.setFading( f );
|
||||
|
||||
fading_target_ = CLAMP(f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
SourceList::iterator Session::begin()
|
||||
{
|
||||
return sources_.begin();
|
||||
}
|
||||
|
||||
SourceList::iterator Session::end()
|
||||
{
|
||||
return sources_.end();
|
||||
}
|
||||
|
||||
SourceList::iterator Session::find(int index)
|
||||
{
|
||||
if (index<0)
|
||||
return sources_.end();
|
||||
|
||||
int i = 0;
|
||||
SourceList::iterator it = sources_.begin();
|
||||
while ( i < index && it != sources_.end() ){
|
||||
i++;
|
||||
it++;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
SourceList::iterator Session::find(Source *s)
|
||||
{
|
||||
return std::find(sources_.begin(), sources_.end(), s);
|
||||
}
|
||||
|
||||
SourceList::iterator Session::find(std::string namesource)
|
||||
{
|
||||
return std::find_if(sources_.begin(), sources_.end(), Source::hasName(namesource));
|
||||
}
|
||||
|
||||
SourceList::iterator Session::find(Node *node)
|
||||
{
|
||||
return std::find_if(sources_.begin(), sources_.end(), Source::hasNode(node));
|
||||
}
|
||||
|
||||
uint Session::numSource() const
|
||||
{
|
||||
return sources_.size();
|
||||
}
|
||||
|
||||
bool Session::empty() const
|
||||
{
|
||||
return sources_.empty();
|
||||
}
|
||||
|
||||
int Session::index(SourceList::iterator it) const
|
||||
{
|
||||
int index = -1;
|
||||
int count = 0;
|
||||
for(auto i = sources_.begin(); i != sources_.end(); i++, count++) {
|
||||
if ( i == it ) {
|
||||
index = count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void Session::addRecorder(Recorder *rec)
|
||||
{
|
||||
recorders_.push_back(rec);
|
||||
}
|
||||
|
||||
|
||||
Recorder *Session::frontRecorder()
|
||||
{
|
||||
if (recorders_.empty())
|
||||
return nullptr;
|
||||
else
|
||||
return recorders_.front();
|
||||
}
|
||||
|
||||
void Session::stopRecorders()
|
||||
{
|
||||
std::list<Recorder *>::iterator iter;
|
||||
for (iter=recorders_.begin(); iter != recorders_.end(); )
|
||||
(*iter)->stop();
|
||||
}
|
||||
|
||||
void Session::clearRecorders()
|
||||
{
|
||||
std::list<Recorder *>::iterator iter;
|
||||
for (iter=recorders_.begin(); iter != recorders_.end(); )
|
||||
{
|
||||
Recorder *rec = *iter;
|
||||
rec->stop();
|
||||
iter = recorders_.erase(iter);
|
||||
delete rec;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::transferRecorders(Session *dest)
|
||||
{
|
||||
if (dest == nullptr)
|
||||
return;
|
||||
|
||||
std::list<Recorder *>::iterator iter;
|
||||
for (iter=recorders_.begin(); iter != recorders_.end(); )
|
||||
{
|
||||
dest->recorders_.push_back(*iter);
|
||||
iter = recorders_.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
82
Session.h
@@ -1,82 +0,0 @@
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
|
||||
#include "View.h"
|
||||
#include "Source.h"
|
||||
|
||||
class Recorder;
|
||||
|
||||
class Session
|
||||
{
|
||||
public:
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
// add given source into the session
|
||||
SourceList::iterator addSource (Source *s);
|
||||
|
||||
// delete the source s from the session
|
||||
SourceList::iterator deleteSource (Source *s);
|
||||
|
||||
// get ptr to front most source and remove it from the session
|
||||
// Does not delete the source
|
||||
Source *popSource();
|
||||
|
||||
// management of list of sources
|
||||
bool empty() const;
|
||||
uint numSource() const;
|
||||
SourceList::iterator begin ();
|
||||
SourceList::iterator end ();
|
||||
SourceList::iterator find (int index);
|
||||
SourceList::iterator find (Source *s);
|
||||
SourceList::iterator find (std::string name);
|
||||
SourceList::iterator find (Node *node);
|
||||
int index (SourceList::iterator it) const;
|
||||
|
||||
// update all sources and mark sources which failed
|
||||
void update (float dt);
|
||||
|
||||
// update mode (active or not)
|
||||
void setActive (bool on);
|
||||
inline bool active () { return active_; }
|
||||
|
||||
// return the last source which failed
|
||||
Source *failedSource() { return failedSource_; }
|
||||
|
||||
// get frame result of render
|
||||
inline FrameBuffer *frame () const { return render_.frame(); }
|
||||
|
||||
// Recorders
|
||||
void addRecorder(Recorder *rec);
|
||||
Recorder *frontRecorder();
|
||||
void stopRecorders();
|
||||
void clearRecorders();
|
||||
void transferRecorders(Session *dest);
|
||||
|
||||
// configure rendering resolution
|
||||
void setResolution(glm::vec3 resolution);
|
||||
|
||||
// manipulate fading of output
|
||||
void setFading(float f, bool forcenow = false);
|
||||
inline float fading() const { return fading_target_; }
|
||||
|
||||
// configuration for group nodes of views
|
||||
inline Group *config (View::Mode m) const { return config_.at(m); }
|
||||
|
||||
// name of file containing this session (for transfer)
|
||||
void setFilename(const std::string &filename) { filename_ = filename; }
|
||||
std::string filename() const { return filename_; }
|
||||
|
||||
protected:
|
||||
RenderView render_;
|
||||
std::string filename_;
|
||||
Source *failedSource_;
|
||||
SourceList sources_;
|
||||
std::map<View::Mode, Group*> config_;
|
||||
bool active_;
|
||||
std::list<Recorder *> recorders_;
|
||||
float fading_target_;
|
||||
};
|
||||
|
||||
#endif // SESSION_H
|
||||
@@ -1,304 +0,0 @@
|
||||
#include "SessionCreator.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "defines.h"
|
||||
#include "Scene.h"
|
||||
#include "Primitives.h"
|
||||
#include "Mesh.h"
|
||||
#include "Source.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "Session.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "MediaPlayer.h"
|
||||
|
||||
#include <tinyxml2.h>
|
||||
using namespace tinyxml2;
|
||||
|
||||
|
||||
std::string SessionCreator::info(const std::string& filename)
|
||||
{
|
||||
std::string ret = "";
|
||||
|
||||
XMLDocument doc;
|
||||
XMLError eResult = doc.LoadFile(filename.c_str());
|
||||
if ( XMLResultError(eResult))
|
||||
return ret;
|
||||
|
||||
XMLElement *header = doc.FirstChildElement(APP_NAME);
|
||||
if (header != nullptr && header->Attribute("date") != 0) {
|
||||
int s = header->IntAttribute("size");
|
||||
ret = std::to_string( s ) + " source" + ( s > 1 ? "s\n" : "\n");
|
||||
std::string date( header->Attribute("date") );
|
||||
ret += date.substr(6,2) + "/" + date.substr(4,2) + "/" + date.substr(0,4) + " ";
|
||||
ret += date.substr(8,2) + ":" + date.substr(10,2) + "\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SessionCreator::SessionCreator(Session *session): Visitor(), session_(session)
|
||||
{
|
||||
xmlDoc_ = new XMLDocument;
|
||||
|
||||
}
|
||||
|
||||
bool SessionCreator::load(const std::string& filename)
|
||||
{
|
||||
XMLError eResult = xmlDoc_->LoadFile(filename.c_str());
|
||||
if ( XMLResultError(eResult))
|
||||
return false;
|
||||
|
||||
XMLElement *header = xmlDoc_->FirstChildElement(APP_NAME);
|
||||
if (header == nullptr) {
|
||||
Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
int version_major = -1, version_minor = -1;
|
||||
header->QueryIntAttribute("major", &version_major); // TODO incompatible if major is different?
|
||||
header->QueryIntAttribute("minor", &version_minor);
|
||||
if (version_major != XML_VERSION_MAJOR || version_minor != XML_VERSION_MINOR){
|
||||
Log::Warning("%s is in a different versions of session file. Loading might fail.", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// ok, ready to read sources
|
||||
loadSession( xmlDoc_->FirstChildElement("Session") );
|
||||
// excellent, session was created: load optionnal config
|
||||
if (session_){
|
||||
loadConfig( xmlDoc_->FirstChildElement("Views") );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionCreator::loadSession(XMLElement *sessionNode)
|
||||
{
|
||||
if (sessionNode != nullptr) {
|
||||
// create a session if not provided
|
||||
if (!session_)
|
||||
session_ = new Session;
|
||||
|
||||
int counter = 0;
|
||||
XMLElement* sourceNode = sessionNode->FirstChildElement("Source");
|
||||
for( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement())
|
||||
{
|
||||
xmlCurrent_ = sourceNode;
|
||||
counter++;
|
||||
|
||||
const char *pType = xmlCurrent_->Attribute("type");
|
||||
if (!pType)
|
||||
continue;
|
||||
if ( std::string(pType) == "MediaSource") {
|
||||
MediaSource *new_media_source = new MediaSource();
|
||||
new_media_source->accept(*this);
|
||||
session_->addSource(new_media_source);
|
||||
}
|
||||
else if ( std::string(pType) == "SessionSource") {
|
||||
SessionSource *new_session_source = new SessionSource();
|
||||
new_session_source->accept(*this);
|
||||
session_->addSource(new_session_source);
|
||||
}
|
||||
else if ( std::string(pType) == "RenderSource") {
|
||||
RenderSource *new_render_source = new RenderSource(session_);
|
||||
new_render_source->accept(*this);
|
||||
session_->addSource(new_render_source);
|
||||
}
|
||||
// TODO : create other types of source
|
||||
|
||||
}
|
||||
|
||||
// create clones after all sources to potentially clone have been created
|
||||
sourceNode = sessionNode->FirstChildElement("Source");
|
||||
for( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement())
|
||||
{
|
||||
xmlCurrent_ = sourceNode;
|
||||
counter++;
|
||||
|
||||
const char *pType = xmlCurrent_->Attribute("type");
|
||||
if (!pType)
|
||||
continue;
|
||||
|
||||
if ( std::string(pType) == "CloneSource") {
|
||||
XMLElement* originNode = xmlCurrent_->FirstChildElement("origin");
|
||||
if (originNode) {
|
||||
std::string sourcename = std::string ( originNode->GetText() );
|
||||
SourceList::iterator origin = session_->find(sourcename);
|
||||
if (origin != session_->end()) {
|
||||
CloneSource *new_clone_source = (*origin)->clone();
|
||||
new_clone_source->accept(*this);
|
||||
session_->addSource(new_clone_source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
Log::Warning("Session seems empty.");
|
||||
}
|
||||
|
||||
void SessionCreator::loadConfig(XMLElement *viewsNode)
|
||||
{
|
||||
if (viewsNode != nullptr) {
|
||||
// ok, ready to read views
|
||||
SessionCreator::XMLToNode( viewsNode->FirstChildElement("Mixing"), *session_->config(View::MIXING));
|
||||
SessionCreator::XMLToNode( viewsNode->FirstChildElement("Geometry"), *session_->config(View::GEOMETRY));
|
||||
SessionCreator::XMLToNode( viewsNode->FirstChildElement("Layer"), *session_->config(View::LAYER));
|
||||
SessionCreator::XMLToNode( viewsNode->FirstChildElement("Rendering"), *session_->config(View::RENDERING));
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::XMLToNode(tinyxml2::XMLElement *xml, Node &n)
|
||||
{
|
||||
if (xml != nullptr){
|
||||
XMLElement *node = xml->FirstChildElement("Node");
|
||||
if ( !node || std::string(node->Name()).find("Node") == std::string::npos )
|
||||
return;
|
||||
|
||||
XMLElement *scaleNode = node->FirstChildElement("scale");
|
||||
if (scaleNode)
|
||||
tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"), n.scale_);
|
||||
XMLElement *translationNode = node->FirstChildElement("translation");
|
||||
if (translationNode)
|
||||
tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"), n.translation_);
|
||||
XMLElement *rotationNode = node->FirstChildElement("rotation");
|
||||
if (rotationNode)
|
||||
tinyxml2::XMLElementToGLM( rotationNode->FirstChildElement("vec3"), n.rotation_);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::visit(Node &n)
|
||||
{
|
||||
XMLToNode(xmlCurrent_, n);
|
||||
}
|
||||
|
||||
void SessionCreator::visit(MediaPlayer &n)
|
||||
{
|
||||
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
||||
if (mediaplayerNode) {
|
||||
double speed = 1.0;
|
||||
mediaplayerNode->QueryDoubleAttribute("speed", &speed);
|
||||
n.setPlaySpeed(speed);
|
||||
int loop = 1;
|
||||
mediaplayerNode->QueryIntAttribute("loop", &loop);
|
||||
n.setLoop( (MediaPlayer::LoopMode) loop);
|
||||
bool play = true;
|
||||
mediaplayerNode->QueryBoolAttribute("play", &play);
|
||||
n.play(play);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::visit(Shader &n)
|
||||
{
|
||||
XMLElement* color = xmlCurrent_->FirstChildElement("color");
|
||||
if ( color ) {
|
||||
tinyxml2::XMLElementToGLM( color->FirstChildElement("vec4"), n.color);
|
||||
XMLElement* blending = xmlCurrent_->FirstChildElement("blending");
|
||||
if (blending) {
|
||||
int blend = 0;
|
||||
blending->QueryIntAttribute("mode", &blend);
|
||||
n.blending = (Shader::BlendMode) blend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::visit(ImageShader &n)
|
||||
{
|
||||
const char *pType = xmlCurrent_->Attribute("type");
|
||||
if ( std::string(pType) != "ImageShader" )
|
||||
return;
|
||||
|
||||
XMLElement* uniforms = xmlCurrent_->FirstChildElement("uniforms");
|
||||
if (uniforms) {
|
||||
uniforms->QueryFloatAttribute("stipple", &n.stipple);
|
||||
uniforms->QueryUnsignedAttribute("mask", &n.mask);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionCreator::visit(ImageProcessingShader &n)
|
||||
{
|
||||
const char *pType = xmlCurrent_->Attribute("type");
|
||||
if ( std::string(pType) != "ImageProcessingShader" )
|
||||
return;
|
||||
|
||||
XMLElement* uniforms = xmlCurrent_->FirstChildElement("uniforms");
|
||||
if (uniforms) {
|
||||
uniforms->QueryFloatAttribute("brightness", &n.brightness);
|
||||
uniforms->QueryFloatAttribute("contrast", &n.contrast);
|
||||
uniforms->QueryFloatAttribute("saturation", &n.saturation);
|
||||
uniforms->QueryFloatAttribute("hueshift", &n.hueshift);
|
||||
uniforms->QueryFloatAttribute("threshold", &n.threshold);
|
||||
uniforms->QueryFloatAttribute("lumakey", &n.lumakey);
|
||||
uniforms->QueryIntAttribute("nbColors", &n.nbColors);
|
||||
uniforms->QueryIntAttribute("invert", &n.invert);
|
||||
uniforms->QueryFloatAttribute("chromadelta", &n.chromadelta);
|
||||
uniforms->QueryIntAttribute("filter", &n.filterid);
|
||||
}
|
||||
|
||||
XMLElement* gamma = xmlCurrent_->FirstChildElement("gamma");
|
||||
if (gamma)
|
||||
tinyxml2::XMLElementToGLM( gamma->FirstChildElement("vec4"), n.gamma);
|
||||
XMLElement* levels = xmlCurrent_->FirstChildElement("levels");
|
||||
if (levels)
|
||||
tinyxml2::XMLElementToGLM( levels->FirstChildElement("vec4"), n.levels);
|
||||
XMLElement* chromakey = xmlCurrent_->FirstChildElement("chromakey");
|
||||
if (chromakey)
|
||||
tinyxml2::XMLElementToGLM( chromakey->FirstChildElement("vec4"), n.chromakey);
|
||||
}
|
||||
|
||||
void SessionCreator::visit (Source& s)
|
||||
{
|
||||
XMLElement* sourceNode = xmlCurrent_;
|
||||
const char *pName = sourceNode->Attribute("name");
|
||||
s.setName(pName);
|
||||
|
||||
xmlCurrent_ = sourceNode->FirstChildElement("Mixing");
|
||||
s.groupNode(View::MIXING)->accept(*this);
|
||||
|
||||
xmlCurrent_ = sourceNode->FirstChildElement("Geometry");
|
||||
s.groupNode(View::GEOMETRY)->accept(*this);
|
||||
|
||||
xmlCurrent_ = sourceNode->FirstChildElement("Layer");
|
||||
s.groupNode(View::LAYER)->accept(*this);
|
||||
|
||||
xmlCurrent_ = sourceNode->FirstChildElement("Blending");
|
||||
s.blendingShader()->accept(*this);
|
||||
|
||||
xmlCurrent_ = sourceNode->FirstChildElement("ImageProcessing");
|
||||
bool on = xmlCurrent_->BoolAttribute("enabled", true);
|
||||
s.processingShader()->accept(*this);
|
||||
s.setImageProcessingEnabled(on);
|
||||
|
||||
// restore current
|
||||
xmlCurrent_ = sourceNode;
|
||||
}
|
||||
|
||||
void SessionCreator::visit (MediaSource& s)
|
||||
{
|
||||
// set uri
|
||||
XMLElement* uriNode = xmlCurrent_->FirstChildElement("uri");
|
||||
if (uriNode) {
|
||||
std::string uri = std::string ( uriNode->GetText() );
|
||||
s.setPath(uri);
|
||||
}
|
||||
|
||||
// set config media player
|
||||
s.mediaplayer()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionCreator::visit (SessionSource& s)
|
||||
{
|
||||
// set uri
|
||||
XMLElement* pathNode = xmlCurrent_->FirstChildElement("path");
|
||||
if (pathNode) {
|
||||
std::string path = std::string ( pathNode->GetText() );
|
||||
s.load(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef SESSIONCREATOR_H
|
||||
#define SESSIONCREATOR_H
|
||||
|
||||
#include "Visitor.h"
|
||||
#include "tinyxml2Toolkit.h"
|
||||
|
||||
class Session;
|
||||
|
||||
class SessionCreator : public Visitor {
|
||||
|
||||
tinyxml2::XMLDocument *xmlDoc_;
|
||||
tinyxml2::XMLElement *xmlCurrent_;
|
||||
Session *session_;
|
||||
|
||||
void loadSession(tinyxml2::XMLElement *sessionNode);
|
||||
void loadConfig(tinyxml2::XMLElement *viewsNode);
|
||||
|
||||
|
||||
public:
|
||||
SessionCreator(Session *session = nullptr);
|
||||
|
||||
bool load(const std::string& filename);
|
||||
inline Session *session() const { return session_; }
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Node& n) override;
|
||||
|
||||
void visit(Scene& n) override {}
|
||||
void visit(Group& n) override {}
|
||||
void visit(Switch& n) override {}
|
||||
void visit(Primitive& n) override {}
|
||||
void visit(Surface& n) override {}
|
||||
void visit(ImageSurface& n) override {}
|
||||
void visit(MediaSurface& n) override {}
|
||||
void visit(FrameBufferSurface& n) override {}
|
||||
void visit(LineStrip& n) override {}
|
||||
void visit(LineSquare&) override {}
|
||||
void visit(LineCircle& n) override {}
|
||||
void visit(Mesh& n) override {}
|
||||
|
||||
// Elements with attributes
|
||||
void visit(MediaPlayer& n) override;
|
||||
void visit(Shader& n) override;
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
|
||||
static std::string info(const std::string& filename);
|
||||
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
||||
};
|
||||
|
||||
|
||||
#endif // SESSIONCREATOR_H
|
||||
@@ -1,329 +0,0 @@
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "SessionSource.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "Resource.h"
|
||||
#include "Primitives.h"
|
||||
#include "Mesh.h"
|
||||
#include "SearchVisitor.h"
|
||||
#include "Session.h"
|
||||
#include "SessionCreator.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
void SessionSource::loadSession(const std::string& filename, SessionSource *source)
|
||||
{
|
||||
source->loadFinished_ = false;
|
||||
|
||||
// actual loading of xml file
|
||||
SessionCreator creator( source->session_ );
|
||||
|
||||
if (creator.load(filename)) {
|
||||
// all ok, validate session filename
|
||||
source->session_->setFilename(filename);
|
||||
}
|
||||
else {
|
||||
// error loading
|
||||
Log::Notify("Failed to load Session file %s.", filename.c_str());
|
||||
source->loadFailed_ = true;
|
||||
}
|
||||
|
||||
// end thread
|
||||
source->loadFinished_ = true;
|
||||
}
|
||||
|
||||
SessionSource::SessionSource() : Source(), path_("")
|
||||
{
|
||||
// specific node for transition view
|
||||
groups_[View::TRANSITION]->visible_ = false;
|
||||
groups_[View::TRANSITION]->scale_ = glm::vec3(0.1f, 0.1f, 1.f);
|
||||
groups_[View::TRANSITION]->translation_ = glm::vec3(-1.f, 0.f, 0.f);
|
||||
|
||||
frames_[View::TRANSITION] = new Switch;
|
||||
Frame *frame = new Frame(Frame::ROUND, Frame::THIN, Frame::DROP);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_DEFAULT_SOURCE, 0.9f);
|
||||
frames_[View::TRANSITION]->attach(frame);
|
||||
frame = new Frame(Frame::ROUND, Frame::LARGE, Frame::DROP);
|
||||
frame->translation_.z = 0.01;
|
||||
frame->color = glm::vec4( COLOR_TRANSITION_SOURCE, 1.f);
|
||||
frames_[View::TRANSITION]->attach(frame);
|
||||
groups_[View::TRANSITION]->attach(frames_[View::TRANSITION]);
|
||||
|
||||
overlays_[View::TRANSITION] = new Group;
|
||||
overlays_[View::TRANSITION]->translation_.z = 0.1;
|
||||
overlays_[View::TRANSITION]->visible_ = false;
|
||||
|
||||
Symbol *loader = new Symbol(Symbol::DOTS);
|
||||
loader->scale_ = glm::vec3(2.f, 2.f, 1.f);
|
||||
loader->update_callbacks_.push_back(new InfiniteGlowCallback);
|
||||
overlays_[View::TRANSITION]->attach(loader);
|
||||
Symbol *center = new Symbol(Symbol::POINT, glm::vec3(0.f, -1.05f, 0.1f));
|
||||
overlays_[View::TRANSITION]->attach(center);
|
||||
groups_[View::TRANSITION]->attach(overlays_[View::TRANSITION]);
|
||||
|
||||
loadFailed_ = false;
|
||||
loadFinished_ = true;
|
||||
wait_for_sources_ = false;
|
||||
|
||||
session_ = new Session;
|
||||
|
||||
// create surface:
|
||||
// - textured with original texture from session
|
||||
// - crop & repeat UV can be managed here
|
||||
// - additional custom shader can be associated
|
||||
sessionsurface_ = new Surface(processingshader_);
|
||||
}
|
||||
|
||||
SessionSource::~SessionSource()
|
||||
{
|
||||
// delete surface
|
||||
delete sessionsurface_;
|
||||
|
||||
// delete session
|
||||
if (session_)
|
||||
delete session_;
|
||||
}
|
||||
|
||||
void SessionSource::load(const std::string &p)
|
||||
{
|
||||
path_ = p;
|
||||
|
||||
// launch a thread to load the session
|
||||
loadFinished_ = false;
|
||||
std::thread ( SessionSource::loadSession, path_, this).detach();
|
||||
|
||||
Log::Notify("Opening %s", p.c_str());
|
||||
}
|
||||
|
||||
Session *SessionSource::detach()
|
||||
{
|
||||
// remember pointer to give away
|
||||
Session *giveaway = session_;
|
||||
|
||||
// work on a new session
|
||||
session_ = new Session;
|
||||
|
||||
// make disabled
|
||||
initialized_ = false;
|
||||
loadFailed_ = true;
|
||||
|
||||
return giveaway;
|
||||
}
|
||||
|
||||
bool SessionSource::failed() const
|
||||
{
|
||||
return loadFailed_;
|
||||
}
|
||||
|
||||
uint SessionSource::texture() const
|
||||
{
|
||||
if (session_ == nullptr)
|
||||
return Resource::getTextureBlack();
|
||||
return session_->frame()->texture();
|
||||
}
|
||||
|
||||
void SessionSource::replaceRenderingShader()
|
||||
{
|
||||
sessionsurface_->replaceShader(renderingshader_);
|
||||
}
|
||||
|
||||
void SessionSource::init()
|
||||
{
|
||||
if (session_ == nullptr)
|
||||
return;
|
||||
|
||||
if (wait_for_sources_) {
|
||||
|
||||
// force update of of all sources
|
||||
active_ = true;
|
||||
touch();
|
||||
|
||||
// check that every source is ready..
|
||||
bool ready = true;
|
||||
for (SourceList::iterator iter = session_->begin(); iter != session_->end(); iter++)
|
||||
{
|
||||
// interrupt if any source is NOT ready
|
||||
if ( !(*iter)->ready() ){
|
||||
ready = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if all sources are ready, done with initialization!
|
||||
if (ready) {
|
||||
// remove the loading icon
|
||||
Node *loader = overlays_[View::TRANSITION]->back();
|
||||
overlays_[View::TRANSITION]->detatch(loader);
|
||||
delete loader;
|
||||
// done init
|
||||
wait_for_sources_ = false;
|
||||
initialized_ = true;
|
||||
Log::Info("Source Session %s loaded %d sources.", path_.c_str(), session_->numSource());
|
||||
}
|
||||
}
|
||||
|
||||
if ( loadFinished_ && !loadFailed_ && session_ != nullptr) {
|
||||
loadFinished_ = false;
|
||||
|
||||
// set resolution
|
||||
session_->setResolution( session_->config(View::RENDERING)->scale_ );
|
||||
|
||||
// deep update once to draw framebuffer
|
||||
View::need_deep_update_ = true;
|
||||
session_->update(dt_);
|
||||
|
||||
// get the texture index from framebuffer of session, apply it to the surface
|
||||
sessionsurface_->setTextureIndex( session_->frame()->texture() );
|
||||
|
||||
// create Frame buffer matching size of session
|
||||
FrameBuffer *renderbuffer = new FrameBuffer( session_->frame()->resolution());
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
|
||||
// icon in mixing view
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::SESSION, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::SESSION, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
|
||||
// wait for all sources to init
|
||||
wait_for_sources_ = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SessionSource::setActive (bool on)
|
||||
{
|
||||
Source::setActive(on);
|
||||
|
||||
// change status of session (recursive change of internal sources)
|
||||
if (session_ != nullptr)
|
||||
session_->setActive(active_);
|
||||
}
|
||||
|
||||
|
||||
void SessionSource::update(float dt)
|
||||
{
|
||||
if (session_ == nullptr)
|
||||
loadFailed_ = true;
|
||||
|
||||
// update content
|
||||
if (active_)
|
||||
session_->update(dt);
|
||||
|
||||
// delete a source which failed
|
||||
if (session_->failedSource() != nullptr) {
|
||||
session_->deleteSource(session_->failedSource());
|
||||
// fail session if all sources failed
|
||||
if ( session_->numSource() < 1)
|
||||
loadFailed_ = true;
|
||||
}
|
||||
|
||||
Source::update(dt);
|
||||
}
|
||||
|
||||
void SessionSource::render()
|
||||
{
|
||||
if (!initialized_)
|
||||
init();
|
||||
else {
|
||||
// render the sesion into frame buffer
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -1.f, 1.f);
|
||||
renderbuffer_->begin();
|
||||
sessionsurface_->draw(glm::identity<glm::mat4>(), projection);
|
||||
renderbuffer_->end();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
RenderSource::RenderSource(Session *session) : Source(), session_(session)
|
||||
{
|
||||
// create surface:
|
||||
sessionsurface_ = new Surface(processingshader_);
|
||||
}
|
||||
|
||||
RenderSource::~RenderSource()
|
||||
{
|
||||
// delete surface
|
||||
delete sessionsurface_;
|
||||
}
|
||||
|
||||
bool RenderSource::failed() const
|
||||
{
|
||||
return session_ == nullptr;
|
||||
}
|
||||
|
||||
uint RenderSource::texture() const
|
||||
{
|
||||
if (session_ == nullptr)
|
||||
return Resource::getTextureBlack();
|
||||
else
|
||||
return session_->frame()->texture();
|
||||
}
|
||||
|
||||
void RenderSource::replaceRenderingShader()
|
||||
{
|
||||
sessionsurface_->replaceShader(renderingshader_);
|
||||
}
|
||||
|
||||
void RenderSource::init()
|
||||
{
|
||||
if (session_ == nullptr)
|
||||
return;
|
||||
|
||||
if (session_ && session_->frame()->texture() != Resource::getTextureBlack()) {
|
||||
|
||||
FrameBuffer *fb = session_->frame();
|
||||
|
||||
// get the texture index from framebuffer of view, apply it to the surface
|
||||
sessionsurface_->setTextureIndex( fb->texture() );
|
||||
|
||||
// create Frame buffer matching size of output session
|
||||
FrameBuffer *renderbuffer = new FrameBuffer( fb->resolution());
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
|
||||
// icon in mixing view
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::RENDER, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::RENDER, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
|
||||
// done init
|
||||
initialized_ = true;
|
||||
|
||||
Log::Info("Source Render linked to session (%d x %d).", int(fb->resolution().x), int(fb->resolution().y) );
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSource::render()
|
||||
{
|
||||
if (!initialized_)
|
||||
init();
|
||||
else {
|
||||
// render the view into frame buffer
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -1.f, 1.f);
|
||||
renderbuffer_->begin();
|
||||
sessionsurface_->draw(glm::identity<glm::mat4>(), projection);
|
||||
renderbuffer_->end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#ifndef SESSIONSOURCE_H
|
||||
#define SESSIONSOURCE_H
|
||||
|
||||
#include <atomic>
|
||||
#include "Source.h"
|
||||
|
||||
class SessionSource : public Source
|
||||
{
|
||||
public:
|
||||
SessionSource();
|
||||
~SessionSource();
|
||||
|
||||
// implementation of source API
|
||||
void update (float dt) override;
|
||||
void setActive (bool on) override;
|
||||
void render() override;
|
||||
bool failed() const override;
|
||||
uint texture() const override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
// Session Source specific interface
|
||||
void load(const std::string &p);
|
||||
Session *detach();
|
||||
|
||||
inline std::string path() const { return path_; }
|
||||
inline Session *session() const { return session_; }
|
||||
|
||||
protected:
|
||||
|
||||
void init() override;
|
||||
void replaceRenderingShader() override;
|
||||
static void loadSession(const std::string& filename, SessionSource *source);
|
||||
|
||||
Surface *sessionsurface_;
|
||||
std::string path_;
|
||||
Session *session_;
|
||||
|
||||
std::atomic<bool> loadFailed_;
|
||||
std::atomic<bool> loadFinished_;
|
||||
std::atomic<bool> wait_for_sources_;
|
||||
};
|
||||
|
||||
|
||||
class RenderSource : public Source
|
||||
{
|
||||
public:
|
||||
RenderSource(Session *session);
|
||||
~RenderSource();
|
||||
|
||||
// implementation of source API
|
||||
void render() override;
|
||||
bool failed() const override;
|
||||
uint texture() const override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
protected:
|
||||
|
||||
void init() override;
|
||||
void replaceRenderingShader() override;
|
||||
Surface *sessionsurface_;
|
||||
Session *session_;
|
||||
};
|
||||
|
||||
|
||||
#endif // SESSIONSOURCE_H
|
||||
@@ -1,362 +0,0 @@
|
||||
#include "SessionVisitor.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Scene.h"
|
||||
#include "Primitives.h"
|
||||
#include "Mesh.h"
|
||||
#include "Source.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "MediaPlayer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
using namespace tinyxml2;
|
||||
|
||||
|
||||
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
||||
tinyxml2::XMLElement *root,
|
||||
bool recursive) : Visitor(), xmlCurrent_(root), recursive_(recursive)
|
||||
{
|
||||
if (doc == nullptr)
|
||||
xmlDoc_ = new XMLDocument;
|
||||
else
|
||||
xmlDoc_ = doc;
|
||||
}
|
||||
|
||||
tinyxml2::XMLElement *SessionVisitor::NodeToXML(Node &n, tinyxml2::XMLDocument *doc)
|
||||
{
|
||||
XMLElement *newelement = doc->NewElement("Node");
|
||||
newelement->SetAttribute("visible", n.visible_);
|
||||
|
||||
XMLElement *scale = doc->NewElement("scale");
|
||||
scale->InsertEndChild( XMLElementFromGLM(doc, n.scale_) );
|
||||
newelement->InsertEndChild(scale);
|
||||
|
||||
XMLElement *translation = doc->NewElement("translation");
|
||||
translation->InsertEndChild( XMLElementFromGLM(doc, n.translation_) );
|
||||
newelement->InsertEndChild(translation);
|
||||
|
||||
XMLElement *rotation = doc->NewElement("rotation");
|
||||
rotation->InsertEndChild( XMLElementFromGLM(doc, n.rotation_) );
|
||||
newelement->InsertEndChild(rotation);
|
||||
|
||||
return newelement;
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Node &n)
|
||||
{
|
||||
XMLElement *newelement = NodeToXML(n, xmlDoc_);
|
||||
|
||||
// insert into hierarchy
|
||||
xmlCurrent_->InsertEndChild(newelement);
|
||||
|
||||
// parent for next visits
|
||||
xmlCurrent_ = newelement;
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Group &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "Group");
|
||||
|
||||
if (recursive_) {
|
||||
// loop over members of a group
|
||||
XMLElement *group = xmlCurrent_;
|
||||
for (NodeSet::iterator node = n.begin(); node != n.end(); node++) {
|
||||
(*node)->accept(*this);
|
||||
// revert to group as current
|
||||
xmlCurrent_ = group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Switch &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "Switch");
|
||||
xmlCurrent_->SetAttribute("active", n.active());
|
||||
|
||||
if (recursive_) {
|
||||
// loop over members of the group
|
||||
XMLElement *group = xmlCurrent_;
|
||||
for(uint i = 0; i < n.numChildren(); i++) {
|
||||
n.child(i)->accept(*this);
|
||||
// revert to group as current
|
||||
xmlCurrent_ = group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Primitive &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "Primitive");
|
||||
|
||||
if (recursive_) {
|
||||
// go over members of a primitive
|
||||
XMLElement *Primitive = xmlCurrent_;
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement("Shader");
|
||||
n.shader()->accept(*this);
|
||||
Primitive->InsertEndChild(xmlCurrent_);
|
||||
|
||||
// revert to primitive as current
|
||||
xmlCurrent_ = Primitive;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SessionVisitor::visit(Surface &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(ImageSurface &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "ImageSurface");
|
||||
|
||||
XMLText *filename = xmlDoc_->NewText( n.resource().c_str() );
|
||||
XMLElement *image = xmlDoc_->NewElement("resource");
|
||||
image->InsertEndChild(filename);
|
||||
xmlCurrent_->InsertEndChild(image);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(FrameBufferSurface &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "FrameBufferSurface");
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(MediaSurface &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "MediaSurface");
|
||||
|
||||
n.mediaPlayer()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(MediaPlayer &n)
|
||||
{
|
||||
XMLElement *newelement = xmlDoc_->NewElement("MediaPlayer");
|
||||
newelement->SetAttribute("play", n.isPlaying());
|
||||
newelement->SetAttribute("loop", (int) n.loop());
|
||||
newelement->SetAttribute("speed", n.playSpeed());
|
||||
|
||||
// TODO Segments
|
||||
|
||||
xmlCurrent_->InsertEndChild(newelement);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Shader &n)
|
||||
{
|
||||
// Shader of a simple type
|
||||
xmlCurrent_->SetAttribute("type", "Shader");
|
||||
|
||||
XMLElement *color = xmlDoc_->NewElement("color");
|
||||
color->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.color) );
|
||||
xmlCurrent_->InsertEndChild(color);
|
||||
|
||||
XMLElement *blend = xmlDoc_->NewElement("blending");
|
||||
blend->SetAttribute("mode", int(n.blending) );
|
||||
xmlCurrent_->InsertEndChild(blend);
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(ImageShader &n)
|
||||
{
|
||||
// Shader of a textured type
|
||||
xmlCurrent_->SetAttribute("type", "ImageShader");
|
||||
|
||||
XMLElement *uniforms = xmlDoc_->NewElement("uniforms");
|
||||
uniforms->SetAttribute("stipple", n.stipple);
|
||||
uniforms->SetAttribute("mask", n.mask);
|
||||
xmlCurrent_->InsertEndChild(uniforms);
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(ImageProcessingShader &n)
|
||||
{
|
||||
// Shader of a textured type
|
||||
xmlCurrent_->SetAttribute("type", "ImageProcessingShader");
|
||||
|
||||
XMLElement *filter = xmlDoc_->NewElement("uniforms");
|
||||
filter->SetAttribute("brightness", n.brightness);
|
||||
filter->SetAttribute("contrast", n.contrast);
|
||||
filter->SetAttribute("saturation", n.saturation);
|
||||
filter->SetAttribute("hueshift", n.hueshift);
|
||||
filter->SetAttribute("threshold", n.threshold);
|
||||
filter->SetAttribute("lumakey", n.lumakey);
|
||||
filter->SetAttribute("nbColors", n.nbColors);
|
||||
filter->SetAttribute("invert", n.invert);
|
||||
filter->SetAttribute("chromadelta", n.chromadelta);
|
||||
filter->SetAttribute("filterid", n.filterid);
|
||||
xmlCurrent_->InsertEndChild(filter);
|
||||
|
||||
XMLElement *gamma = xmlDoc_->NewElement("gamma");
|
||||
gamma->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.gamma) );
|
||||
xmlCurrent_->InsertEndChild(gamma);
|
||||
|
||||
XMLElement *levels = xmlDoc_->NewElement("levels");
|
||||
levels->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.levels) );
|
||||
xmlCurrent_->InsertEndChild(levels);
|
||||
|
||||
XMLElement *chromakey = xmlDoc_->NewElement("chromakey");
|
||||
chromakey->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.chromakey) );
|
||||
xmlCurrent_->InsertEndChild(chromakey);
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(LineStrip &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "LineStrip");
|
||||
|
||||
XMLElement *points_node = xmlDoc_->NewElement("points");
|
||||
std::vector<glm::vec3> points = n.getPoints();
|
||||
for(size_t i = 0; i < points.size(); ++i)
|
||||
{
|
||||
XMLElement *p = XMLElementFromGLM(xmlDoc_, points[i]);
|
||||
p->SetAttribute("index", (int) i);
|
||||
points_node->InsertEndChild(p);
|
||||
}
|
||||
xmlCurrent_->InsertEndChild(points_node);
|
||||
|
||||
XMLElement *colors_node = xmlDoc_->NewElement("colors");
|
||||
std::vector<glm::vec4> colors = n.getColors();
|
||||
for(size_t i = 0; i < colors.size(); ++i)
|
||||
{
|
||||
XMLElement *p = XMLElementFromGLM(xmlDoc_, colors[i]);
|
||||
p->SetAttribute("index", (int) i);
|
||||
colors_node->InsertEndChild(p);
|
||||
}
|
||||
xmlCurrent_->InsertEndChild(colors_node);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(LineSquare &)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "LineSquare");
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(LineCircle &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "LineCircle");
|
||||
|
||||
// XMLElement *color = xmlDoc_->NewElement("color");
|
||||
// color->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.getColor()) );
|
||||
// xmlCurrent_->InsertEndChild(color);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Mesh &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "Mesh");
|
||||
|
||||
XMLText *filename = xmlDoc_->NewText( n.meshPath().c_str() );
|
||||
XMLElement *obj = xmlDoc_->NewElement("resource");
|
||||
obj->InsertEndChild(filename);
|
||||
xmlCurrent_->InsertEndChild(obj);
|
||||
|
||||
filename = xmlDoc_->NewText( n.texturePath().c_str() );
|
||||
XMLElement *tex = xmlDoc_->NewElement("texture");
|
||||
tex->InsertEndChild(filename);
|
||||
xmlCurrent_->InsertEndChild(tex);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Frame &n)
|
||||
{
|
||||
// Node of a different type
|
||||
xmlCurrent_->SetAttribute("type", "Frame");
|
||||
|
||||
XMLElement *color = xmlDoc_->NewElement("color");
|
||||
color->InsertEndChild( XMLElementFromGLM(xmlDoc_, n.color) );
|
||||
xmlCurrent_->InsertEndChild(color);
|
||||
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Scene &n)
|
||||
{
|
||||
XMLElement *xmlRoot = xmlDoc_->NewElement("Scene");
|
||||
xmlDoc_->InsertEndChild(xmlRoot);
|
||||
|
||||
// start recursive traverse from root node
|
||||
recursive_ = true;
|
||||
xmlCurrent_ = xmlRoot;
|
||||
n.root()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (Source& s)
|
||||
{
|
||||
XMLElement *sourceNode = xmlDoc_->NewElement( "Source" );
|
||||
sourceNode->SetAttribute("name", s.name().c_str() );
|
||||
|
||||
// insert into hierarchy
|
||||
xmlCurrent_->InsertFirstChild(sourceNode);
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "Mixing" );
|
||||
sourceNode->InsertEndChild(xmlCurrent_);
|
||||
s.groupNode(View::MIXING)->accept(*this);
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "Geometry" );
|
||||
sourceNode->InsertEndChild(xmlCurrent_);
|
||||
s.groupNode(View::GEOMETRY)->accept(*this);
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "Layer" );
|
||||
sourceNode->InsertEndChild(xmlCurrent_);
|
||||
s.groupNode(View::LAYER)->accept(*this);
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "Blending" );
|
||||
sourceNode->InsertEndChild(xmlCurrent_);
|
||||
s.blendingShader()->accept(*this);
|
||||
|
||||
xmlCurrent_ = xmlDoc_->NewElement( "ImageProcessing" );
|
||||
xmlCurrent_->SetAttribute("enabled", s.imageProcessingEnabled());
|
||||
sourceNode->InsertEndChild(xmlCurrent_);
|
||||
s.processingShader()->accept(*this);
|
||||
|
||||
xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source)
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (MediaSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "MediaSource");
|
||||
|
||||
XMLElement *uri = xmlDoc_->NewElement("uri");
|
||||
xmlCurrent_->InsertEndChild(uri);
|
||||
XMLText *text = xmlDoc_->NewText( s.path().c_str() );
|
||||
uri->InsertEndChild( text );
|
||||
|
||||
s.mediaplayer()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (SessionSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "SessionSource");
|
||||
|
||||
XMLElement *path = xmlDoc_->NewElement("path");
|
||||
xmlCurrent_->InsertEndChild(path);
|
||||
XMLText *text = xmlDoc_->NewText( s.path().c_str() );
|
||||
path->InsertEndChild( text );
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (RenderSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "RenderSource");
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (CloneSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "CloneSource");
|
||||
|
||||
XMLElement *origin = xmlDoc_->NewElement("origin");
|
||||
xmlCurrent_->InsertEndChild(origin);
|
||||
XMLText *text = xmlDoc_->NewText( s.origin()->name().c_str() );
|
||||
origin->InsertEndChild( text );
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef XMLVISITOR_H
|
||||
#define XMLVISITOR_H
|
||||
|
||||
#include "Visitor.h"
|
||||
#include "tinyxml2Toolkit.h"
|
||||
|
||||
class SessionVisitor : public Visitor {
|
||||
|
||||
bool recursive_;
|
||||
tinyxml2::XMLDocument *xmlDoc_;
|
||||
tinyxml2::XMLElement *xmlCurrent_;
|
||||
|
||||
public:
|
||||
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
||||
tinyxml2::XMLElement *root = nullptr,
|
||||
bool recursive = false);
|
||||
|
||||
inline tinyxml2::XMLDocument *doc() const { return xmlDoc_; }
|
||||
|
||||
// Elements of Scene
|
||||
void visit(Scene& n) override;
|
||||
void visit(Node& n) override;
|
||||
void visit(Group& n) override;
|
||||
void visit(Switch& n) override;
|
||||
void visit(Primitive& n) override;
|
||||
void visit(Surface& n) override;
|
||||
void visit(ImageSurface& n) override;
|
||||
void visit(MediaSurface& n) override;
|
||||
void visit(FrameBufferSurface& n) override;
|
||||
void visit(LineStrip& n) override;
|
||||
void visit(LineSquare&) override;
|
||||
void visit(LineCircle& n) override;
|
||||
void visit(Mesh& n) override;
|
||||
void visit(Frame& n) override;
|
||||
|
||||
// Elements with attributes
|
||||
void visit(MediaPlayer& n) override;
|
||||
void visit(Shader& n) override;
|
||||
void visit(ImageShader& n) override;
|
||||
void visit(ImageProcessingShader& n) override;
|
||||
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (RenderSource& s) override;
|
||||
void visit (CloneSource& s) override;
|
||||
|
||||
static tinyxml2::XMLElement *NodeToXML(Node &n, tinyxml2::XMLDocument *doc);
|
||||
};
|
||||
|
||||
#endif // XMLVISITOR_H
|
||||
378
Settings.cpp
@@ -1,378 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include <tinyxml2.h>
|
||||
#include "tinyxml2Toolkit.h"
|
||||
using namespace tinyxml2;
|
||||
|
||||
#include "defines.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemToolkit.h"
|
||||
|
||||
|
||||
Settings::Application Settings::application;
|
||||
static string settingsFilename = "";
|
||||
|
||||
void Settings::Save()
|
||||
{
|
||||
XMLDocument xmlDoc;
|
||||
XMLDeclaration *pDec = xmlDoc.NewDeclaration();
|
||||
xmlDoc.InsertFirstChild(pDec);
|
||||
|
||||
XMLElement *pRoot = xmlDoc.NewElement(application.name.c_str());
|
||||
xmlDoc.InsertEndChild(pRoot);
|
||||
|
||||
string comment = "Settings for " + application.name;
|
||||
comment += "Version " + std::to_string(APP_VERSION_MAJOR) + "." + std::to_string(APP_VERSION_MINOR);
|
||||
XMLComment *pComment = xmlDoc.NewComment(comment.c_str());
|
||||
pRoot->InsertEndChild(pComment);
|
||||
|
||||
// block: windows
|
||||
{
|
||||
XMLElement *windowsNode = xmlDoc.NewElement( "Windows" );
|
||||
|
||||
for (int i = 0; i < application.windows.size(); i++)
|
||||
{
|
||||
const Settings::WindowConfig& w = application.windows[i];
|
||||
|
||||
XMLElement *window = xmlDoc.NewElement( "Window" );
|
||||
window->SetAttribute("id", i);
|
||||
window->SetAttribute("name", w.name.c_str());
|
||||
window->SetAttribute("x", w.x);
|
||||
window->SetAttribute("y", w.y);
|
||||
window->SetAttribute("w", w.w);
|
||||
window->SetAttribute("h", w.h);
|
||||
window->SetAttribute("f", w.fullscreen);
|
||||
window->SetAttribute("m", w.monitor.c_str());
|
||||
windowsNode->InsertEndChild(window);
|
||||
}
|
||||
|
||||
pRoot->InsertEndChild(windowsNode);
|
||||
}
|
||||
|
||||
// General application preferences
|
||||
XMLElement *applicationNode = xmlDoc.NewElement( "Application" );
|
||||
applicationNode->SetAttribute("scale", application.scale);
|
||||
applicationNode->SetAttribute("accent_color", application.accent_color);
|
||||
applicationNode->SetAttribute("pannel_stick", application.pannel_stick);
|
||||
applicationNode->SetAttribute("smooth_transition", application.smooth_transition);
|
||||
pRoot->InsertEndChild(applicationNode);
|
||||
|
||||
// Widgets
|
||||
XMLElement *widgetsNode = xmlDoc.NewElement( "Widgets" );
|
||||
widgetsNode->SetAttribute("preview", application.widget.preview);
|
||||
widgetsNode->SetAttribute("media_player", application.widget.media_player);
|
||||
widgetsNode->SetAttribute("shader_editor", application.widget.shader_editor);
|
||||
widgetsNode->SetAttribute("stats", application.widget.stats);
|
||||
widgetsNode->SetAttribute("stats_corner", application.widget.stats_corner);
|
||||
widgetsNode->SetAttribute("logs", application.widget.logs);
|
||||
widgetsNode->SetAttribute("toolbox", application.widget.toolbox);
|
||||
pRoot->InsertEndChild(widgetsNode);
|
||||
|
||||
// Render
|
||||
XMLElement *RenderNode = xmlDoc.NewElement( "Render" );
|
||||
RenderNode->SetAttribute("vsync", application.render.vsync);
|
||||
RenderNode->SetAttribute("multisampling", application.render.multisampling);
|
||||
RenderNode->SetAttribute("blit", application.render.blit);
|
||||
RenderNode->SetAttribute("ratio", application.render.ratio);
|
||||
RenderNode->SetAttribute("res", application.render.res);
|
||||
pRoot->InsertEndChild(RenderNode);
|
||||
|
||||
// Record
|
||||
XMLElement *RecordNode = xmlDoc.NewElement( "Record" );
|
||||
RecordNode->SetAttribute("path", application.record.path.c_str());
|
||||
RecordNode->SetAttribute("profile", application.record.profile);
|
||||
RecordNode->SetAttribute("timeout", application.record.timeout);
|
||||
pRoot->InsertEndChild(RecordNode);
|
||||
|
||||
// Transition
|
||||
XMLElement *TransitionNode = xmlDoc.NewElement( "Transition" );
|
||||
TransitionNode->SetAttribute("auto_open", application.transition.auto_open);
|
||||
TransitionNode->SetAttribute("hide_windows", application.transition.hide_windows);
|
||||
TransitionNode->SetAttribute("cross_fade", application.transition.cross_fade);
|
||||
TransitionNode->SetAttribute("duration", application.transition.duration);
|
||||
TransitionNode->SetAttribute("profile", application.transition.profile);
|
||||
pRoot->InsertEndChild(TransitionNode);
|
||||
|
||||
// bloc views
|
||||
{
|
||||
XMLElement *viewsNode = xmlDoc.NewElement( "Views" );
|
||||
// save current view only if [mixing, geometry or layers]
|
||||
int v = application.current_view > 3 ? 1 : application.current_view;
|
||||
viewsNode->SetAttribute("current", v);
|
||||
|
||||
map<int, Settings::ViewConfig>::iterator iter;
|
||||
for (iter=application.views.begin(); iter != application.views.end(); iter++)
|
||||
{
|
||||
const Settings::ViewConfig& v = iter->second;
|
||||
|
||||
XMLElement *view = xmlDoc.NewElement( "View" );
|
||||
view->SetAttribute("name", v.name.c_str());
|
||||
view->SetAttribute("id", iter->first);
|
||||
|
||||
XMLElement *scale = xmlDoc.NewElement("default_scale");
|
||||
scale->InsertEndChild( XMLElementFromGLM(&xmlDoc, v.default_scale) );
|
||||
view->InsertEndChild(scale);
|
||||
XMLElement *translation = xmlDoc.NewElement("default_translation");
|
||||
translation->InsertEndChild( XMLElementFromGLM(&xmlDoc, v.default_translation) );
|
||||
view->InsertEndChild(translation);
|
||||
|
||||
viewsNode->InsertEndChild(view);
|
||||
}
|
||||
|
||||
pRoot->InsertEndChild(viewsNode);
|
||||
}
|
||||
|
||||
// bloc history
|
||||
{
|
||||
XMLElement *recent = xmlDoc.NewElement( "Recent" );
|
||||
|
||||
XMLElement *recentsession = xmlDoc.NewElement( "Session" );
|
||||
recentsession->SetAttribute("path", application.recentSessions.path.c_str());
|
||||
recentsession->SetAttribute("autoload", application.recentSessions.load_at_start);
|
||||
recentsession->SetAttribute("autosave", application.recentSessions.save_on_exit);
|
||||
recentsession->SetAttribute("valid", application.recentSessions.valid_file);
|
||||
for(auto it = application.recentSessions.filenames.begin();
|
||||
it != application.recentSessions.filenames.end(); it++) {
|
||||
XMLElement *fileNode = xmlDoc.NewElement("path");
|
||||
XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||
fileNode->InsertEndChild( text );
|
||||
recentsession->InsertFirstChild(fileNode);
|
||||
};
|
||||
recent->InsertEndChild(recentsession);
|
||||
|
||||
XMLElement *recentfolder = xmlDoc.NewElement( "Folder" );
|
||||
for(auto it = application.recentFolders.filenames.begin();
|
||||
it != application.recentFolders.filenames.end(); it++) {
|
||||
XMLElement *fileNode = xmlDoc.NewElement("path");
|
||||
XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||
fileNode->InsertEndChild( text );
|
||||
recentfolder->InsertFirstChild(fileNode);
|
||||
};
|
||||
recent->InsertEndChild(recentfolder);
|
||||
|
||||
XMLElement *recentmedia = xmlDoc.NewElement( "Import" );
|
||||
recentmedia->SetAttribute("path", application.recentImport.path.c_str());
|
||||
for(auto it = application.recentImport.filenames.begin();
|
||||
it != application.recentImport.filenames.end(); it++) {
|
||||
XMLElement *fileNode = xmlDoc.NewElement("path");
|
||||
XMLText *text = xmlDoc.NewText( (*it).c_str() );
|
||||
fileNode->InsertEndChild( text );
|
||||
recentmedia->InsertFirstChild(fileNode);
|
||||
}
|
||||
recent->InsertEndChild(recentmedia);
|
||||
|
||||
pRoot->InsertEndChild(recent);
|
||||
}
|
||||
|
||||
|
||||
// First save : create filename
|
||||
if (settingsFilename.empty())
|
||||
settingsFilename = SystemToolkit::full_filename(SystemToolkit::settings_path(), APP_SETTINGS);
|
||||
|
||||
XMLError eResult = xmlDoc.SaveFile(settingsFilename.c_str());
|
||||
XMLResultError(eResult);
|
||||
}
|
||||
|
||||
void Settings::Load()
|
||||
{
|
||||
XMLDocument xmlDoc;
|
||||
if (settingsFilename.empty())
|
||||
settingsFilename = SystemToolkit::full_filename(SystemToolkit::settings_path(), APP_SETTINGS);
|
||||
XMLError eResult = xmlDoc.LoadFile(settingsFilename.c_str());
|
||||
|
||||
// do not warn if non existing file
|
||||
if (eResult == XML_ERROR_FILE_NOT_FOUND)
|
||||
return;
|
||||
// warn and return on other error
|
||||
else if (XMLResultError(eResult))
|
||||
return;
|
||||
|
||||
XMLElement *pRoot = xmlDoc.FirstChildElement(application.name.c_str());
|
||||
if (pRoot == nullptr) return;
|
||||
|
||||
if (application.name.compare( string( pRoot->Value() ) ) != 0 )
|
||||
// different root name
|
||||
return;
|
||||
|
||||
XMLElement * applicationNode = pRoot->FirstChildElement("Application");
|
||||
if (applicationNode != nullptr) {
|
||||
applicationNode->QueryFloatAttribute("scale", &application.scale);
|
||||
applicationNode->QueryIntAttribute("accent_color", &application.accent_color);
|
||||
applicationNode->QueryBoolAttribute("pannel_stick", &application.pannel_stick);
|
||||
applicationNode->QueryBoolAttribute("smooth_transition", &application.smooth_transition);
|
||||
}
|
||||
|
||||
// Widgets
|
||||
XMLElement * widgetsNode = pRoot->FirstChildElement("Widgets");
|
||||
if (widgetsNode != nullptr) {
|
||||
widgetsNode->QueryBoolAttribute("preview", &application.widget.preview);
|
||||
widgetsNode->QueryBoolAttribute("media_player", &application.widget.media_player);
|
||||
widgetsNode->QueryBoolAttribute("shader_editor", &application.widget.shader_editor);
|
||||
widgetsNode->QueryBoolAttribute("stats", &application.widget.stats);
|
||||
widgetsNode->QueryIntAttribute("stats_corner", &application.widget.stats_corner);
|
||||
widgetsNode->QueryBoolAttribute("logs", &application.widget.logs);
|
||||
widgetsNode->QueryBoolAttribute("toolbox", &application.widget.toolbox);
|
||||
}
|
||||
|
||||
// Render
|
||||
XMLElement * rendernode = pRoot->FirstChildElement("Render");
|
||||
if (rendernode != nullptr) {
|
||||
rendernode->QueryIntAttribute("vsync", &application.render.vsync);
|
||||
rendernode->QueryIntAttribute("multisampling", &application.render.multisampling);
|
||||
rendernode->QueryBoolAttribute("blit", &application.render.blit);
|
||||
rendernode->QueryIntAttribute("ratio", &application.render.ratio);
|
||||
rendernode->QueryIntAttribute("res", &application.render.res);
|
||||
}
|
||||
|
||||
// Record
|
||||
XMLElement * recordnode = pRoot->FirstChildElement("Record");
|
||||
if (recordnode != nullptr) {
|
||||
recordnode->QueryIntAttribute("profile", &application.record.profile);
|
||||
recordnode->QueryFloatAttribute("timeout", &application.record.timeout);
|
||||
|
||||
const char *path_ = recordnode->Attribute("path");
|
||||
if (path_)
|
||||
application.record.path = std::string(path_);
|
||||
else
|
||||
application.record.path = SystemToolkit::home_path();
|
||||
}
|
||||
|
||||
// Transition
|
||||
XMLElement * transitionnode = pRoot->FirstChildElement("Transition");
|
||||
if (transitionnode != nullptr) {
|
||||
transitionnode->QueryBoolAttribute("hide_windows", &application.transition.hide_windows);
|
||||
transitionnode->QueryBoolAttribute("auto_open", &application.transition.auto_open);
|
||||
transitionnode->QueryBoolAttribute("cross_fade", &application.transition.cross_fade);
|
||||
transitionnode->QueryFloatAttribute("duration", &application.transition.duration);
|
||||
transitionnode->QueryIntAttribute("profile", &application.transition.profile);
|
||||
}
|
||||
|
||||
// bloc windows
|
||||
{
|
||||
XMLElement * pElement = pRoot->FirstChildElement("Windows");
|
||||
if (pElement)
|
||||
{
|
||||
XMLElement* windowNode = pElement->FirstChildElement("Window");
|
||||
for( ; windowNode ; windowNode=windowNode->NextSiblingElement())
|
||||
{
|
||||
Settings::WindowConfig w;
|
||||
w.name = std::string(windowNode->Attribute("name"));
|
||||
windowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is
|
||||
windowNode->QueryIntAttribute("y", &w.y);
|
||||
windowNode->QueryIntAttribute("w", &w.w);
|
||||
windowNode->QueryIntAttribute("h", &w.h);
|
||||
windowNode->QueryBoolAttribute("f", &w.fullscreen);
|
||||
w.monitor = std::string(windowNode->Attribute("m"));
|
||||
|
||||
int i = 0;
|
||||
windowNode->QueryIntAttribute("id", &i);
|
||||
application.windows[i] = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bloc views
|
||||
{
|
||||
application.views.clear(); // trash existing list
|
||||
XMLElement * pElement = pRoot->FirstChildElement("Views");
|
||||
if (pElement)
|
||||
{
|
||||
pElement->QueryIntAttribute("current", &application.current_view);
|
||||
|
||||
XMLElement* viewNode = pElement->FirstChildElement("View");
|
||||
for( ; viewNode ; viewNode=viewNode->NextSiblingElement())
|
||||
{
|
||||
int id = 0;
|
||||
viewNode->QueryIntAttribute("id", &id);
|
||||
application.views[id].name = viewNode->Attribute("name");
|
||||
|
||||
XMLElement* scaleNode = viewNode->FirstChildElement("default_scale");
|
||||
tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"),
|
||||
application.views[id].default_scale);
|
||||
|
||||
XMLElement* translationNode = viewNode->FirstChildElement("default_translation");
|
||||
tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"),
|
||||
application.views[id].default_translation);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// bloc history of recent
|
||||
{
|
||||
XMLElement * pElement = pRoot->FirstChildElement("Recent");
|
||||
if (pElement)
|
||||
{
|
||||
// recent session filenames
|
||||
XMLElement * pSession = pElement->FirstChildElement("Session");
|
||||
if (pSession)
|
||||
{
|
||||
const char *path_ = pSession->Attribute("path");
|
||||
if (path_)
|
||||
application.recentSessions.path = std::string(path_);
|
||||
else
|
||||
application.recentSessions.path = SystemToolkit::home_path();
|
||||
application.recentSessions.filenames.clear();
|
||||
XMLElement* path = pSession->FirstChildElement("path");
|
||||
for( ; path ; path = path->NextSiblingElement())
|
||||
{
|
||||
const char *p = path->GetText();
|
||||
if (p)
|
||||
application.recentSessions.push( std::string (p) );
|
||||
}
|
||||
pSession->QueryBoolAttribute("autoload", &application.recentSessions.load_at_start);
|
||||
pSession->QueryBoolAttribute("autosave", &application.recentSessions.save_on_exit);
|
||||
pSession->QueryBoolAttribute("valid", &application.recentSessions.valid_file);
|
||||
}
|
||||
// recent session filenames
|
||||
XMLElement * pFolder = pElement->FirstChildElement("Folder");
|
||||
if (pFolder)
|
||||
{
|
||||
application.recentFolders.filenames.clear();
|
||||
XMLElement* path = pFolder->FirstChildElement("path");
|
||||
for( ; path ; path = path->NextSiblingElement())
|
||||
{
|
||||
const char *p = path->GetText();
|
||||
if (p)
|
||||
application.recentFolders.push( std::string (p) );
|
||||
}
|
||||
}
|
||||
// recent media uri
|
||||
XMLElement * pImport = pElement->FirstChildElement("Import");
|
||||
if (pImport)
|
||||
{
|
||||
const char *path_ = pImport->Attribute("path");
|
||||
if (path_)
|
||||
application.recentImport.path = std::string(path_);
|
||||
else
|
||||
application.recentImport.path = SystemToolkit::home_path();
|
||||
application.recentImport.filenames.clear();
|
||||
XMLElement* path = pImport->FirstChildElement("path");
|
||||
for( ; path ; path = path->NextSiblingElement())
|
||||
{
|
||||
const char *p = path->GetText();
|
||||
if (p)
|
||||
application.recentImport.push( std::string (p) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Settings::Check()
|
||||
{
|
||||
Settings::Save();
|
||||
|
||||
XMLDocument xmlDoc;
|
||||
XMLError eResult = xmlDoc.LoadFile(settingsFilename.c_str());
|
||||
if (XMLResultError(eResult))
|
||||
return;
|
||||
|
||||
xmlDoc.Print();
|
||||
}
|
||||
202
Settings.h
@@ -1,202 +0,0 @@
|
||||
#ifndef __SETTINGS_H_
|
||||
#define __SETTINGS_H_
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace Settings {
|
||||
|
||||
struct WidgetsConfig
|
||||
{
|
||||
bool stats;
|
||||
int stats_corner;
|
||||
bool logs;
|
||||
bool preview;
|
||||
bool media_player;
|
||||
bool media_player_view;
|
||||
bool shader_editor;
|
||||
bool toolbox;
|
||||
|
||||
WidgetsConfig() {
|
||||
stats = false;
|
||||
stats_corner = 1;
|
||||
logs = false;
|
||||
preview = false;
|
||||
media_player = false;
|
||||
media_player_view = true;
|
||||
shader_editor = false;
|
||||
toolbox = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct WindowConfig
|
||||
{
|
||||
std::string name;
|
||||
int x,y,w,h;
|
||||
bool fullscreen;
|
||||
std::string monitor;
|
||||
|
||||
WindowConfig() : name(""), x(15), y(15), w(1280), h(720), fullscreen(false), monitor("") { }
|
||||
|
||||
};
|
||||
|
||||
struct ViewConfig
|
||||
{
|
||||
std::string name;
|
||||
glm::vec3 default_scale;
|
||||
glm::vec3 default_translation;
|
||||
|
||||
ViewConfig() : name("") {
|
||||
default_scale = glm::vec3(1.f);
|
||||
default_translation = glm::vec3(0.f);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define RECORD_MAX_TIMEOUT 1800.f
|
||||
|
||||
struct RecordConfig
|
||||
{
|
||||
std::string path;
|
||||
int profile;
|
||||
float timeout;
|
||||
|
||||
RecordConfig() : path("") {
|
||||
profile = 0;
|
||||
timeout = RECORD_MAX_TIMEOUT;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct History
|
||||
{
|
||||
std::string path;
|
||||
std::list<std::string> filenames;
|
||||
bool valid_file;
|
||||
bool load_at_start;
|
||||
bool save_on_exit;
|
||||
|
||||
History() {
|
||||
path = IMGUI_LABEL_RECENT_FILES;
|
||||
valid_file = false;
|
||||
load_at_start = false;
|
||||
save_on_exit = false;
|
||||
}
|
||||
void push(std::string filename) {
|
||||
if (filename.empty()) {
|
||||
valid_file = false;
|
||||
return;
|
||||
}
|
||||
filenames.remove(filename);
|
||||
filenames.push_front(filename);
|
||||
if (filenames.size() > MAX_RECENT_HISTORY)
|
||||
filenames.pop_back();
|
||||
valid_file = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct TransitionConfig
|
||||
{
|
||||
bool cross_fade;
|
||||
bool auto_open;
|
||||
bool hide_windows;
|
||||
float duration;
|
||||
int profile;
|
||||
|
||||
TransitionConfig() {
|
||||
cross_fade = true;
|
||||
auto_open = true;
|
||||
hide_windows = true;
|
||||
duration = 1.f;
|
||||
profile = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderConfig
|
||||
{
|
||||
bool blit;
|
||||
int vsync;
|
||||
int multisampling;
|
||||
int ratio;
|
||||
int res;
|
||||
float fading;
|
||||
|
||||
RenderConfig() {
|
||||
blit = false;
|
||||
vsync = 1; // todo GUI selection
|
||||
multisampling = 2; // todo GUI selection
|
||||
ratio = 3;
|
||||
res = 1;
|
||||
fading = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Application
|
||||
{
|
||||
// Verification
|
||||
std::string name;
|
||||
std::string executable;
|
||||
|
||||
// Global settings Application interface
|
||||
float scale;
|
||||
int accent_color;
|
||||
bool pannel_stick;
|
||||
bool smooth_transition;
|
||||
|
||||
// Settings of widgets
|
||||
WidgetsConfig widget;
|
||||
|
||||
// Settings of Views
|
||||
int current_view;
|
||||
std::map<int, ViewConfig> views;
|
||||
|
||||
// settings render
|
||||
RenderConfig render;
|
||||
|
||||
// settings render
|
||||
RecordConfig record;
|
||||
|
||||
// settings transition
|
||||
TransitionConfig transition;
|
||||
|
||||
// multiple windows handling
|
||||
std::vector<WindowConfig> windows;
|
||||
|
||||
// recent files histories
|
||||
History recentSessions;
|
||||
History recentFolders;
|
||||
History recentImport;
|
||||
|
||||
Application() : name(APP_NAME){
|
||||
scale = 1.f;
|
||||
accent_color = 0;
|
||||
pannel_stick = false;
|
||||
smooth_transition = true;
|
||||
current_view = 1;
|
||||
windows = std::vector<WindowConfig>(3);
|
||||
windows[0].name = APP_NAME APP_TITLE;
|
||||
windows[0].w = 1600;
|
||||
windows[0].h = 900;
|
||||
windows[1].name = APP_NAME " -- Output";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// minimal implementation of settings
|
||||
// Can be accessed r&w anywhere
|
||||
extern Application application;
|
||||
|
||||
// Save and Load store settings in XML file
|
||||
void Save();
|
||||
void Load();
|
||||
void Check();
|
||||
|
||||
}
|
||||
|
||||
#endif /* __SETTINGS_H_ */
|
||||
243
Shader.cpp
@@ -1,243 +0,0 @@
|
||||
#include "Shader.h"
|
||||
#include "Resource.h"
|
||||
#include "Log.h"
|
||||
#include "Visitor.h"
|
||||
#include "RenderingManager.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
// Globals
|
||||
ShadingProgram *ShadingProgram::currentProgram_ = nullptr;
|
||||
ShadingProgram simpleShadingProgram("shaders/simple.vs", "shaders/simple.fs");
|
||||
|
||||
// Blending presets for matching with Shader::BlendMode
|
||||
GLenum blending_equation[6] = { GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD};
|
||||
GLenum blending_source_function[6] = { GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA};
|
||||
GLenum blending_destination_function[6] = {GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE, GL_DST_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA};
|
||||
|
||||
|
||||
|
||||
ShadingProgram::ShadingProgram(const std::string& vertex_file, const std::string& fragment_file) : vertex_id_(0), fragment_id_(0), id_(0)
|
||||
{
|
||||
vertex_file_ = vertex_file;
|
||||
fragment_file_ = fragment_file;
|
||||
}
|
||||
|
||||
void ShadingProgram::init()
|
||||
{
|
||||
vertex_code_ = Resource::getText(vertex_file_);
|
||||
fragment_code_ = Resource::getText(fragment_file_);
|
||||
compile();
|
||||
link();
|
||||
}
|
||||
|
||||
bool ShadingProgram::initialized()
|
||||
{
|
||||
return (id_ != 0);
|
||||
}
|
||||
|
||||
void ShadingProgram::compile()
|
||||
{
|
||||
const char* vcode = vertex_code_.c_str();
|
||||
vertex_id_ = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex_id_, 1, &vcode, NULL);
|
||||
glCompileShader(vertex_id_);
|
||||
|
||||
const char* fcode = fragment_code_.c_str();
|
||||
fragment_id_ = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment_id_, 1, &fcode, NULL);
|
||||
glCompileShader(fragment_id_);
|
||||
|
||||
checkCompileErr();
|
||||
}
|
||||
|
||||
void ShadingProgram::link()
|
||||
{
|
||||
id_ = glCreateProgram();
|
||||
glAttachShader(id_, vertex_id_);
|
||||
glAttachShader(id_, fragment_id_);
|
||||
glLinkProgram(id_);
|
||||
checkLinkingErr();
|
||||
glUseProgram(id_);
|
||||
glUniform1i(glGetUniformLocation(id_, "iChannel0"), 0);
|
||||
glUniform1i(glGetUniformLocation(id_, "iChannel1"), 1);
|
||||
glUseProgram(0);
|
||||
glDeleteShader(vertex_id_);
|
||||
glDeleteShader(fragment_id_);
|
||||
}
|
||||
|
||||
void ShadingProgram::use()
|
||||
{
|
||||
if (currentProgram_ == nullptr || currentProgram_ != this)
|
||||
{
|
||||
currentProgram_ = this;
|
||||
glUseProgram(id_);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadingProgram::enduse()
|
||||
{
|
||||
glUseProgram(0);
|
||||
currentProgram_ = nullptr ;
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<int>(const std::string& name, int val) {
|
||||
glUniform1i(glGetUniformLocation(id_, name.c_str()), val);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<bool>(const std::string& name, bool val) {
|
||||
glUniform1i(glGetUniformLocation(id_, name.c_str()), val);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<float>(const std::string& name, float val) {
|
||||
glUniform1f(glGetUniformLocation(id_, name.c_str()), val);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2) {
|
||||
glUniform2f(glGetUniformLocation(id_, name.c_str()), val1, val2);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2, float val3) {
|
||||
glUniform3f(glGetUniformLocation(id_, name.c_str()), val1, val2, val3);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<glm::vec4>(const std::string& name, glm::vec4 val) {
|
||||
glm::vec4 v(val);
|
||||
glUniform4fv(glGetUniformLocation(id_, name.c_str()), 1, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<glm::vec3>(const std::string& name, glm::vec3 val) {
|
||||
glm::vec3 v(val);
|
||||
glUniform4fv(glGetUniformLocation(id_, name.c_str()), 1, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
template<>
|
||||
void ShadingProgram::setUniform<glm::mat4>(const std::string& name, glm::mat4 val) {
|
||||
glm::mat4 m(val);
|
||||
glUniformMatrix4fv(glGetUniformLocation(id_, name.c_str()), 1, GL_FALSE, glm::value_ptr(m));
|
||||
}
|
||||
|
||||
|
||||
// template<>
|
||||
// void ShadingProgram::setUniform<float*>(const std::string& name, float* val) {
|
||||
// glUniformMatrix4fv(glGetUniformLocation(id_, name.c_str()), 1, GL_FALSE, val);
|
||||
// }
|
||||
|
||||
void ShadingProgram::checkCompileErr()
|
||||
{
|
||||
int success;
|
||||
char infoLog[1024];
|
||||
glGetShaderiv(vertex_id_, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(vertex_id_, 1024, NULL, infoLog);
|
||||
Log::Warning("Error compiling Vertex ShadingProgram:\n%s", infoLog);
|
||||
}
|
||||
glGetShaderiv(fragment_id_, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(fragment_id_, 1024, NULL, infoLog);
|
||||
Log::Warning("Error compiling Fragment ShadingProgram:\n%s", infoLog);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadingProgram::checkLinkingErr()
|
||||
{
|
||||
int success;
|
||||
char infoLog[1024];
|
||||
glGetProgramiv(id_, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetProgramInfoLog(id_, 1024, NULL, infoLog);
|
||||
Log::Warning("Error linking ShadingProgram:\n%s", infoLog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Shader::force_blending_opacity = false;
|
||||
|
||||
Shader::Shader() : blending(BLEND_OPACITY)
|
||||
{
|
||||
// create unique id
|
||||
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
|
||||
id_ = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 100000000;
|
||||
|
||||
program_ = &simpleShadingProgram;
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void Shader::operator = (const Shader &S )
|
||||
{
|
||||
color = S.color;
|
||||
blending = S.blending;
|
||||
}
|
||||
|
||||
void Shader::accept(Visitor& v) {
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
void Shader::use()
|
||||
{
|
||||
// initialization on first use
|
||||
if (!program_->initialized())
|
||||
program_->init();
|
||||
|
||||
// Use program and set uniforms
|
||||
program_->use();
|
||||
|
||||
// set uniforms
|
||||
program_->setUniform("projection", projection);
|
||||
program_->setUniform("modelview", modelview);
|
||||
program_->setUniform("color", color);
|
||||
|
||||
iResolution = glm::vec3( Rendering::manager().currentAttrib().viewport, 0.f);
|
||||
program_->setUniform("iResolution", iResolution);
|
||||
|
||||
// Blending Function
|
||||
if (force_blending_opacity) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(blending_equation[BLEND_OPACITY]);
|
||||
glBlendFunc(blending_source_function[BLEND_OPACITY], blending_destination_function[BLEND_OPACITY]);
|
||||
|
||||
}
|
||||
else if ( blending != BLEND_CUSTOM ) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(blending_equation[blending]);
|
||||
glBlendFunc(blending_source_function[blending], blending_destination_function[blending]);
|
||||
|
||||
// TODO different blending for alpha and color
|
||||
// glBlendEquationSeparate(blending_equation[blending], GL_FUNC_ADD);
|
||||
// glBlendFuncSeparate(blending_source_function[blending], blending_destination_function[blending], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
}
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
|
||||
void Shader::reset()
|
||||
{
|
||||
projection = glm::identity<glm::mat4>();
|
||||
modelview = glm::identity<glm::mat4>();
|
||||
iResolution = glm::vec3(1280.f, 720.f, 0.f);
|
||||
color = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
|
||||
77
Shader.h
@@ -1,77 +0,0 @@
|
||||
#ifndef __SHADER_H_
|
||||
#define __SHADER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// Forward declare classes referenced
|
||||
class Visitor;
|
||||
|
||||
class ShadingProgram
|
||||
{
|
||||
public:
|
||||
ShadingProgram(const std::string& vertex_file, const std::string& fragment_file);
|
||||
void init();
|
||||
bool initialized();
|
||||
void use();
|
||||
template<typename T> void setUniform(const std::string& name, T val);
|
||||
template<typename T> void setUniform(const std::string& name, T val1, T val2);
|
||||
template<typename T> void setUniform(const std::string& name, T val1, T val2, T val3);
|
||||
|
||||
static void enduse();
|
||||
|
||||
private:
|
||||
void checkCompileErr();
|
||||
void checkLinkingErr();
|
||||
void compile();
|
||||
void link();
|
||||
unsigned int vertex_id_, fragment_id_, id_;
|
||||
std::string vertex_code_;
|
||||
std::string fragment_code_;
|
||||
std::string vertex_file_;
|
||||
std::string fragment_file_;
|
||||
|
||||
static ShadingProgram *currentProgram_;
|
||||
};
|
||||
|
||||
class Shader
|
||||
{
|
||||
int id_;
|
||||
|
||||
public:
|
||||
Shader();
|
||||
|
||||
// unique identifyer generated at instanciation
|
||||
inline int id () const { return id_; }
|
||||
|
||||
virtual void use();
|
||||
virtual void reset();
|
||||
virtual void accept(Visitor& v);
|
||||
|
||||
void operator = (const Shader &D );
|
||||
|
||||
glm::mat4 projection;
|
||||
glm::mat4 modelview;
|
||||
glm::vec4 color;
|
||||
|
||||
typedef enum {
|
||||
BLEND_OPACITY = 0,
|
||||
BLEND_ADD,
|
||||
BLEND_SUBSTRACT,
|
||||
BLEND_LAYER_ADD,
|
||||
BLEND_LAYER_SUBSTRACT,
|
||||
BLEND_CUSTOM
|
||||
} BlendMode;
|
||||
BlendMode blending;
|
||||
|
||||
static bool force_blending_opacity;
|
||||
|
||||
protected:
|
||||
ShadingProgram *program_;
|
||||
glm::vec3 iResolution;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __SHADER_H_ */
|
||||
489
Source.cpp
@@ -1,489 +0,0 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "Source.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Primitives.h"
|
||||
#include "Decorations.h"
|
||||
#include "Mesh.h"
|
||||
#include "Resource.h"
|
||||
#include "Session.h"
|
||||
#include "SearchVisitor.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "Log.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
Source::Source() : initialized_(false), active_(true), need_update_(true)
|
||||
{
|
||||
sprintf(initials_, "__");
|
||||
name_ = "Source";
|
||||
mode_ = Source::UNINITIALIZED;
|
||||
|
||||
// create groups and overlays for each view
|
||||
|
||||
// default rendering node
|
||||
groups_[View::RENDERING] = new Group;
|
||||
groups_[View::RENDERING]->visible_ = false;
|
||||
|
||||
// default mixing nodes
|
||||
groups_[View::MIXING] = new Group;
|
||||
groups_[View::MIXING]->visible_ = false;
|
||||
groups_[View::MIXING]->scale_ = glm::vec3(0.15f, 0.15f, 1.f);
|
||||
groups_[View::MIXING]->translation_ = glm::vec3(-1.f, 1.f, 0.f);
|
||||
|
||||
frames_[View::MIXING] = new Switch;
|
||||
Frame *frame = new Frame(Frame::ROUND, Frame::THIN, Frame::DROP);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_DEFAULT_SOURCE, 0.9f);
|
||||
frames_[View::MIXING]->attach(frame);
|
||||
frame = new Frame(Frame::ROUND, Frame::LARGE, Frame::DROP);
|
||||
frame->translation_.z = 0.01;
|
||||
frame->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
frames_[View::MIXING]->attach(frame);
|
||||
groups_[View::MIXING]->attach(frames_[View::MIXING]);
|
||||
|
||||
overlays_[View::MIXING] = new Group;
|
||||
overlays_[View::MIXING]->translation_.z = 0.1;
|
||||
overlays_[View::MIXING]->visible_ = false;
|
||||
Symbol *center = new Symbol(Symbol::POINT, glm::vec3(0.f, 0.f, 0.1f));
|
||||
overlays_[View::MIXING]->attach(center);
|
||||
groups_[View::MIXING]->attach(overlays_[View::MIXING]);
|
||||
|
||||
// default geometry nodes
|
||||
groups_[View::GEOMETRY] = new Group;
|
||||
groups_[View::GEOMETRY]->visible_ = false;
|
||||
|
||||
frames_[View::GEOMETRY] = new Switch;
|
||||
frame = new Frame(Frame::SHARP, Frame::THIN, Frame::NONE);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_DEFAULT_SOURCE, 0.7f);
|
||||
frames_[View::GEOMETRY]->attach(frame);
|
||||
frame = new Frame(Frame::SHARP, Frame::LARGE, Frame::GLOW);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
frames_[View::GEOMETRY]->attach(frame);
|
||||
groups_[View::GEOMETRY]->attach(frames_[View::GEOMETRY]);
|
||||
|
||||
overlays_[View::GEOMETRY] = new Group;
|
||||
overlays_[View::GEOMETRY]->translation_.z = 0.15;
|
||||
overlays_[View::GEOMETRY]->visible_ = false;
|
||||
handle_[Handles::RESIZE] = new Handles(Handles::RESIZE);
|
||||
handle_[Handles::RESIZE]->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
handle_[Handles::RESIZE]->translation_.z = 0.1;
|
||||
overlays_[View::GEOMETRY]->attach(handle_[Handles::RESIZE]);
|
||||
handle_[Handles::RESIZE_H] = new Handles(Handles::RESIZE_H);
|
||||
handle_[Handles::RESIZE_H]->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
handle_[Handles::RESIZE_H]->translation_.z = 0.1;
|
||||
overlays_[View::GEOMETRY]->attach(handle_[Handles::RESIZE_H]);
|
||||
handle_[Handles::RESIZE_V] = new Handles(Handles::RESIZE_V);
|
||||
handle_[Handles::RESIZE_V]->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
handle_[Handles::RESIZE_V]->translation_.z = 0.1;
|
||||
overlays_[View::GEOMETRY]->attach(handle_[Handles::RESIZE_V]);
|
||||
handle_[Handles::ROTATE] = new Handles(Handles::ROTATE);
|
||||
handle_[Handles::ROTATE]->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
handle_[Handles::ROTATE]->translation_.z = 0.1;
|
||||
overlays_[View::GEOMETRY]->attach(handle_[Handles::ROTATE]);
|
||||
frame = new Frame(Frame::SHARP, Frame::THIN, Frame::NONE);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 0.7f);
|
||||
overlays_[View::GEOMETRY]->attach(frame);
|
||||
groups_[View::GEOMETRY]->attach(overlays_[View::GEOMETRY]);
|
||||
|
||||
// default layer nodes
|
||||
groups_[View::LAYER] = new Group;
|
||||
groups_[View::LAYER]->visible_ = false;
|
||||
|
||||
frames_[View::LAYER] = new Switch;
|
||||
frame = new Frame(Frame::ROUND, Frame::THIN, Frame::PERSPECTIVE);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_DEFAULT_SOURCE, 0.8f);
|
||||
frames_[View::LAYER]->attach(frame);
|
||||
frame = new Frame(Frame::ROUND, Frame::LARGE, Frame::PERSPECTIVE);
|
||||
frame->translation_.z = 0.1;
|
||||
frame->color = glm::vec4( COLOR_HIGHLIGHT_SOURCE, 1.f);
|
||||
frames_[View::LAYER]->attach(frame);
|
||||
groups_[View::LAYER]->attach(frames_[View::LAYER]);
|
||||
|
||||
overlays_[View::LAYER] = new Group;
|
||||
overlays_[View::LAYER]->translation_.z = 0.15;
|
||||
overlays_[View::LAYER]->visible_ = false;
|
||||
groups_[View::LAYER]->attach(overlays_[View::LAYER]);
|
||||
|
||||
// empty transition node
|
||||
groups_[View::TRANSITION] = new Group;
|
||||
|
||||
// create objects
|
||||
stored_status_ = new Group;
|
||||
|
||||
// those will be associated to nodes later
|
||||
blendingshader_ = new ImageShader;
|
||||
processingshader_ = new ImageProcessingShader;
|
||||
// default to image processing enabled
|
||||
renderingshader_ = (Shader *) processingshader_;
|
||||
|
||||
renderbuffer_ = nullptr;
|
||||
rendersurface_ = nullptr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Source::~Source()
|
||||
{
|
||||
// delete objects
|
||||
delete stored_status_;
|
||||
if (renderbuffer_)
|
||||
delete renderbuffer_;
|
||||
|
||||
// all groups and their children are deleted in the scene
|
||||
// this includes rendersurface_, overlays, blendingshader_ and rendershader_
|
||||
delete groups_[View::RENDERING];
|
||||
delete groups_[View::MIXING];
|
||||
delete groups_[View::GEOMETRY];
|
||||
delete groups_[View::LAYER];
|
||||
delete groups_[View::TRANSITION];
|
||||
|
||||
groups_.clear();
|
||||
frames_.clear();
|
||||
overlays_.clear();
|
||||
|
||||
// inform clones that they lost their origin
|
||||
for (auto it = clones_.begin(); it != clones_.end(); it++)
|
||||
(*it)->origin_ = nullptr;
|
||||
|
||||
}
|
||||
|
||||
void Source::setName (const std::string &name)
|
||||
{
|
||||
name_ = name;
|
||||
|
||||
initials_[0] = std::toupper( name_.front() );
|
||||
initials_[1] = std::toupper( name_.back() );
|
||||
}
|
||||
|
||||
void Source::accept(Visitor& v)
|
||||
{
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
Source::Mode Source::mode() const
|
||||
{
|
||||
return mode_;
|
||||
}
|
||||
|
||||
void Source::setMode(Source::Mode m)
|
||||
{
|
||||
// make visible on first time
|
||||
if ( mode_ == Source::UNINITIALIZED ) {
|
||||
for (auto g = groups_.begin(); g != groups_.end(); g++)
|
||||
(*g).second->visible_ = true;
|
||||
}
|
||||
|
||||
// choose frame if selected
|
||||
uint index_frame = m == Source::VISIBLE ? 0 : 1;
|
||||
for (auto f = frames_.begin(); f != frames_.end(); f++)
|
||||
(*f).second->setActive(index_frame);
|
||||
|
||||
// show overlay if current
|
||||
bool current = m == Source::CURRENT;
|
||||
for (auto o = overlays_.begin(); o != overlays_.end(); o++)
|
||||
(*o).second->visible_ = current;
|
||||
|
||||
mode_ = m;
|
||||
}
|
||||
|
||||
|
||||
void Source::setImageProcessingEnabled (bool on)
|
||||
{
|
||||
// avoid repeating
|
||||
if ( on == imageProcessingEnabled() )
|
||||
return;
|
||||
|
||||
// set pointer
|
||||
if (on) {
|
||||
// set the current rendering shader to be the
|
||||
// (previously prepared) processing shader
|
||||
renderingshader_ = (Shader *) processingshader_;
|
||||
}
|
||||
else {
|
||||
// clone the current Image processing shader
|
||||
// (because the one currently attached to the source
|
||||
// will be deleted in replaceRenderngShader().)
|
||||
ImageProcessingShader *tmp = new ImageProcessingShader(*processingshader_);
|
||||
// loose reference to current processing shader (to delete)
|
||||
// and keep reference to the newly created one
|
||||
// and keep it for later
|
||||
processingshader_ = tmp;
|
||||
// set the current rendering shader to a simple one
|
||||
renderingshader_ = (Shader *) new ImageShader;
|
||||
}
|
||||
|
||||
// apply to nodes in subclasses
|
||||
// this calls replaceShader() on the Primitive and
|
||||
// will delete the previously attached shader
|
||||
replaceRenderingShader();
|
||||
}
|
||||
|
||||
bool Source::imageProcessingEnabled()
|
||||
{
|
||||
return ( renderingshader_ == processingshader_ );
|
||||
}
|
||||
|
||||
void Source::attach(FrameBuffer *renderbuffer)
|
||||
{
|
||||
renderbuffer_ = renderbuffer;
|
||||
|
||||
// create the surfaces to draw the frame buffer in the views
|
||||
rendersurface_ = new FrameBufferSurface(renderbuffer_, blendingshader_);
|
||||
groups_[View::RENDERING]->attach(rendersurface_);
|
||||
groups_[View::GEOMETRY]->attach(rendersurface_);
|
||||
groups_[View::MIXING]->attach(rendersurface_);
|
||||
// groups_[View::LAYER]->attach(rendersurface_);
|
||||
|
||||
// for mixing and layer views, add another surface to overlay
|
||||
// (stippled view on top with transparency)
|
||||
Surface *surfacemix = new FrameBufferSurface(renderbuffer_);
|
||||
ImageShader *is = static_cast<ImageShader *>(surfacemix->shader());
|
||||
if (is) is->stipple = 1.0;
|
||||
groups_[View::MIXING]->attach(surfacemix);
|
||||
groups_[View::LAYER]->attach(surfacemix);
|
||||
|
||||
// scale all icon nodes to match aspect ratio of the media
|
||||
NodeSet::iterator node;
|
||||
for (node = groups_[View::MIXING]->begin();
|
||||
node != groups_[View::MIXING]->end(); node++) {
|
||||
(*node)->scale_.x = renderbuffer_->aspectRatio();
|
||||
}
|
||||
for (node = groups_[View::GEOMETRY]->begin();
|
||||
node != groups_[View::GEOMETRY]->end(); node++) {
|
||||
(*node)->scale_.x = renderbuffer_->aspectRatio();
|
||||
}
|
||||
for (node = groups_[View::LAYER]->begin();
|
||||
node != groups_[View::LAYER]->end(); node++) {
|
||||
(*node)->scale_.x = renderbuffer_->aspectRatio();
|
||||
}
|
||||
|
||||
// Transition group node is optionnal
|
||||
if ( groups_[View::TRANSITION]->numChildren() > 0 ) {
|
||||
groups_[View::TRANSITION]->attach(rendersurface_);
|
||||
groups_[View::TRANSITION]->attach(surfacemix);
|
||||
for (NodeSet::iterator node = groups_[View::TRANSITION]->begin();
|
||||
node != groups_[View::TRANSITION]->end(); node++) {
|
||||
(*node)->scale_.x = renderbuffer_->aspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
// make the source visible
|
||||
if ( mode_ == UNINITIALIZED )
|
||||
setMode(VISIBLE);
|
||||
}
|
||||
|
||||
void Source::setActive (bool on)
|
||||
{
|
||||
active_ = on;
|
||||
|
||||
for(auto clone = clones_.begin(); clone != clones_.end(); clone++) {
|
||||
if ( (*clone)->active() )
|
||||
active_ = true;
|
||||
}
|
||||
|
||||
groups_[View::RENDERING]->visible_ = active_;
|
||||
groups_[View::GEOMETRY]->visible_ = active_;
|
||||
groups_[View::LAYER]->visible_ = active_;
|
||||
|
||||
}
|
||||
// Transfer functions from coordinates to alpha (1 - transparency)
|
||||
float linear_(float x, float y) {
|
||||
return 1.f - CLAMP( sqrt( ( x * x ) + ( y * y ) ), 0.f, 1.f );
|
||||
}
|
||||
|
||||
float quad_(float x, float y) {
|
||||
return 1.f - CLAMP( ( x * x ) + ( y * y ), 0.f, 1.f );
|
||||
}
|
||||
|
||||
float sin_quad(float x, float y) {
|
||||
return 0.5f + 0.5f * cos( M_PI * CLAMP( ( ( x * x ) + ( y * y ) ), 0.f, 1.f ) );
|
||||
}
|
||||
|
||||
void Source::update(float dt)
|
||||
{
|
||||
// keep delta-t
|
||||
dt_ = dt;
|
||||
|
||||
// update nodes if needed
|
||||
if (need_update_)
|
||||
{
|
||||
// ADJUST alpha based on MIXING node
|
||||
// read position of the mixing node and interpret this as transparency of render output
|
||||
glm::vec2 dist = glm::vec2(groups_[View::MIXING]->translation_);
|
||||
// use the prefered transfer function
|
||||
blendingshader_->color.a = sin_quad( dist.x, dist.y );
|
||||
|
||||
// CHANGE update status based on limbo
|
||||
setActive( glm::length(dist) < 1.3f );
|
||||
|
||||
// MODIFY geometry based on GEOMETRY node
|
||||
groups_[View::RENDERING]->translation_ = groups_[View::GEOMETRY]->translation_;
|
||||
groups_[View::RENDERING]->rotation_ = groups_[View::GEOMETRY]->rotation_;
|
||||
// avoid any null scale
|
||||
glm::vec3 s = groups_[View::GEOMETRY]->scale_;
|
||||
s.x = CLAMP_SCALE(s.x);
|
||||
s.y = CLAMP_SCALE(s.y);
|
||||
s.z = 1.f;
|
||||
groups_[View::GEOMETRY]->scale_ = s;
|
||||
groups_[View::RENDERING]->scale_ = s;
|
||||
|
||||
// MODIFY depth based on LAYER node
|
||||
groups_[View::MIXING]->translation_.z = groups_[View::LAYER]->translation_.z;
|
||||
groups_[View::GEOMETRY]->translation_.z = groups_[View::LAYER]->translation_.z;
|
||||
groups_[View::RENDERING]->translation_.z = groups_[View::LAYER]->translation_.z;
|
||||
|
||||
need_update_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer *Source::frame() const
|
||||
{
|
||||
if (initialized_ && renderbuffer_)
|
||||
{
|
||||
return renderbuffer_;
|
||||
}
|
||||
else {
|
||||
static FrameBuffer *black = new FrameBuffer(640,480);
|
||||
return black;
|
||||
}
|
||||
}
|
||||
|
||||
bool Source::contains(Node *node) const
|
||||
{
|
||||
if ( node == nullptr )
|
||||
return false;
|
||||
|
||||
hasNode tester(node);
|
||||
return tester(this);
|
||||
}
|
||||
|
||||
|
||||
bool Source::hasNode::operator()(const Source* elem) const
|
||||
{
|
||||
if (_n && elem)
|
||||
{
|
||||
// quick case (most frequent and easy to answer)
|
||||
if (elem->rendersurface_ == _n)
|
||||
return true;
|
||||
|
||||
// general case: traverse tree of all Groups recursively using a SearchVisitor
|
||||
SearchVisitor sv(_n);
|
||||
for (auto g = elem->groups_.begin(); g != elem->groups_.end(); g++) {
|
||||
(*g).second->accept(sv);
|
||||
if (sv.found())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CloneSource *Source::clone()
|
||||
{
|
||||
CloneSource *s = new CloneSource(this);
|
||||
|
||||
clones_.push_back(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
CloneSource::CloneSource(Source *origin) : Source(), origin_(origin)
|
||||
{
|
||||
// create surface:
|
||||
clonesurface_ = new Surface(renderingshader_);
|
||||
}
|
||||
|
||||
CloneSource::~CloneSource()
|
||||
{
|
||||
// delete surface
|
||||
delete clonesurface_;
|
||||
}
|
||||
|
||||
CloneSource *CloneSource::clone()
|
||||
{
|
||||
// do not clone a clone : clone the original instead
|
||||
if (origin_)
|
||||
return origin_->clone();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CloneSource::replaceRenderingShader()
|
||||
{
|
||||
clonesurface_->replaceShader(renderingshader_);
|
||||
}
|
||||
|
||||
void CloneSource::init()
|
||||
{
|
||||
if (origin_ && origin_->ready()) {
|
||||
|
||||
// get the texture index from framebuffer of view, apply it to the surface
|
||||
clonesurface_->setTextureIndex( origin_->texture() );
|
||||
|
||||
// create Frame buffer matching size of session
|
||||
FrameBuffer *renderbuffer = new FrameBuffer( origin_->frame()->resolution(), true);
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
|
||||
// icon in mixing view
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::CLONE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::CLONE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
|
||||
// done init
|
||||
initialized_ = true;
|
||||
|
||||
Log::Info("Source Clone linked to source %s).", origin_->name().c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
void CloneSource::setActive (bool on)
|
||||
{
|
||||
active_ = on;
|
||||
|
||||
groups_[View::RENDERING]->visible_ = active_;
|
||||
groups_[View::GEOMETRY]->visible_ = active_;
|
||||
groups_[View::LAYER]->visible_ = active_;
|
||||
|
||||
if (origin_)
|
||||
origin_->touch();
|
||||
}
|
||||
|
||||
|
||||
uint CloneSource::texture() const
|
||||
{
|
||||
if (origin_)
|
||||
return origin_->texture();
|
||||
else
|
||||
return Resource::getTextureBlack();
|
||||
}
|
||||
|
||||
void CloneSource::render()
|
||||
{
|
||||
if (!initialized_)
|
||||
init();
|
||||
else {
|
||||
// render the view into frame buffer
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -1.f, 1.f);
|
||||
renderbuffer_->begin();
|
||||
clonesurface_->draw(glm::identity<glm::mat4>(), projection);
|
||||
renderbuffer_->end();
|
||||
}
|
||||
}
|
||||
|
||||
void CloneSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
206
Source.h
@@ -1,206 +0,0 @@
|
||||
#ifndef SOURCE_H
|
||||
#define SOURCE_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include "View.h"
|
||||
#include "Decorations.h"
|
||||
|
||||
class ImageShader;
|
||||
class ImageProcessingShader;
|
||||
class FrameBuffer;
|
||||
class FrameBufferSurface;
|
||||
class MediaPlayer;
|
||||
class Surface;
|
||||
class Session;
|
||||
class Frame;
|
||||
class Source;
|
||||
class CloneSource;
|
||||
|
||||
typedef std::list<Source *> SourceList;
|
||||
typedef std::list<CloneSource *> CloneList;
|
||||
|
||||
class Source
|
||||
{
|
||||
friend class View;
|
||||
friend class MixingView;
|
||||
friend class GeometryView;
|
||||
friend class LayerView;
|
||||
friend class TransitionView;
|
||||
|
||||
public:
|
||||
// create a source and add it to the list
|
||||
// only subclasses of sources can actually be instanciated
|
||||
Source();
|
||||
virtual ~Source();
|
||||
|
||||
// manipulate name of source
|
||||
void setName (const std::string &name);
|
||||
inline std::string name () const { return name_; }
|
||||
inline const char *initials () const { return initials_; }
|
||||
|
||||
// cloning mechanism
|
||||
virtual CloneSource *clone ();
|
||||
inline size_t numClones() const { return clones_.size(); }
|
||||
|
||||
// Display mode
|
||||
typedef enum {
|
||||
UNINITIALIZED = 0,
|
||||
VISIBLE = 1,
|
||||
SELECTED = 2,
|
||||
CURRENT = 3
|
||||
} Mode;
|
||||
Mode mode () const;
|
||||
void setMode (Mode m);
|
||||
|
||||
// get handle on the nodes used to manipulate the source in a view
|
||||
inline Group *group (View::Mode m) const { return groups_.at(m); }
|
||||
inline Node *groupNode (View::Mode m) const { return static_cast<Node*>(groups_.at(m)); }
|
||||
|
||||
// tests if a given node is part of the source
|
||||
bool contains (Node *node) const;
|
||||
|
||||
// a Source has a shader used to render in fbo
|
||||
inline Shader *renderingShader() const { return renderingshader_; }
|
||||
|
||||
// the rendering shader always have an image processing shader
|
||||
inline ImageProcessingShader *processingShader () const { return processingshader_; }
|
||||
|
||||
// the image processing shader can be enabled or disabled
|
||||
// (NB: when disabled, a simple ImageShader is applied)
|
||||
void setImageProcessingEnabled (bool on);
|
||||
bool imageProcessingEnabled();
|
||||
|
||||
// a Source has a shader to control mixing effects
|
||||
inline ImageShader *blendingShader () const { return blendingshader_; }
|
||||
|
||||
// every Source has a frame buffer from the renderbuffer
|
||||
virtual FrameBuffer *frame () const;
|
||||
|
||||
// touch to request update
|
||||
inline void touch () { need_update_ = true; }
|
||||
|
||||
// informs if its ready (i.e. initialized)
|
||||
inline bool ready() const { return initialized_; }
|
||||
|
||||
// a Source shall be updated before displayed (Mixing, Geometry and Layer)
|
||||
virtual void update (float dt);
|
||||
|
||||
// update mode
|
||||
virtual void setActive (bool on);
|
||||
inline bool active () { return active_; }
|
||||
|
||||
// a Source shall informs if the source failed (i.e. shall be deleted)
|
||||
virtual bool failed() const = 0;
|
||||
|
||||
// a Source shall define a way to get a texture
|
||||
virtual uint texture() const = 0;
|
||||
|
||||
// a Source shall define how to render into the frame buffer
|
||||
virtual void render() = 0;
|
||||
|
||||
// accept all kind of visitors
|
||||
virtual void accept (Visitor& v);
|
||||
|
||||
struct hasNode: public std::unary_function<Source*, bool>
|
||||
{
|
||||
bool operator()(const Source* elem) const;
|
||||
hasNode(Node *n) : _n(n) { }
|
||||
private:
|
||||
Node *_n;
|
||||
};
|
||||
|
||||
struct hasName: public std::unary_function<Source*, bool>
|
||||
{
|
||||
inline bool operator()(const Source* elem) const {
|
||||
return (elem && elem->name() == _n);
|
||||
}
|
||||
hasName(std::string n) : _n(n) { }
|
||||
private:
|
||||
std::string _n;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
// name
|
||||
std::string name_;
|
||||
char initials_[3];
|
||||
|
||||
// every Source shall be initialized on first draw
|
||||
bool initialized_;
|
||||
virtual void init() = 0;
|
||||
|
||||
// nodes
|
||||
std::map<View::Mode, Group*> groups_;
|
||||
|
||||
// render() fills in the renderbuffer at every frame
|
||||
// NB: rendershader_ is applied at render()
|
||||
FrameBuffer *renderbuffer_;
|
||||
void attach(FrameBuffer *renderbuffer);
|
||||
|
||||
// the rendersurface draws the renderbuffer in the scene
|
||||
// It is associated to the rendershader for mixing effects
|
||||
FrameBufferSurface *rendersurface_;
|
||||
|
||||
// image processing shaders
|
||||
ImageProcessingShader *processingshader_;
|
||||
// pointer to the currently attached shader
|
||||
// (will be processingshader_ if image processing is enabled)
|
||||
Shader *renderingshader_;
|
||||
// every sub class will attach the shader to a different node / hierarchy
|
||||
virtual void replaceRenderingShader() = 0;
|
||||
|
||||
// blendingshader provides mixing controls
|
||||
ImageShader *blendingshader_;
|
||||
|
||||
// mode for display
|
||||
Mode mode_;
|
||||
|
||||
// overlays and frames to be displayed on top of source
|
||||
std::map<View::Mode, Group*> overlays_;
|
||||
std::map<View::Mode, Switch*> frames_;
|
||||
Handles *handle_[4];
|
||||
|
||||
// update
|
||||
bool active_;
|
||||
bool need_update_;
|
||||
float dt_;
|
||||
Group *stored_status_;
|
||||
|
||||
// clones
|
||||
CloneList clones_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CloneSource : public Source
|
||||
{
|
||||
friend class Source;
|
||||
|
||||
public:
|
||||
~CloneSource();
|
||||
|
||||
// implementation of source API
|
||||
void setActive (bool on) override;
|
||||
void render() override;
|
||||
uint texture() const override;
|
||||
bool failed() const override { return origin_ == nullptr; }
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
CloneSource *clone() override;
|
||||
inline Source *origin() const { return origin_; }
|
||||
|
||||
protected:
|
||||
// only Source class can create new CloneSource via clone();
|
||||
CloneSource(Source *origin);
|
||||
|
||||
void init() override;
|
||||
void replaceRenderingShader() override;
|
||||
Surface *clonesurface_;
|
||||
Source *origin_;
|
||||
};
|
||||
|
||||
|
||||
#endif // SOURCE_H
|
||||
@@ -1,312 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#define mkdir(dir, mode) _mkdir(dir)
|
||||
#include <include/dirent.h>
|
||||
#include <sys/resource.h>
|
||||
#define PATH_SEP '\\'
|
||||
#define PATH_SETTINGS "\\\AppData\\Roaming\\"
|
||||
#elif defined(LINUX) or defined(APPLE)
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <dirent.h>
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
#if defined(APPLE)
|
||||
#define PATH_SETTINGS "/Library/Application Support/"
|
||||
#include <mach/task.h>
|
||||
#include <mach/mach_init.h>
|
||||
#elif defined(LINUX)
|
||||
#include <sys/sysinfo.h>
|
||||
#define PATH_SETTINGS "/.config/"
|
||||
#endif
|
||||
|
||||
#include "defines.h"
|
||||
#include "SystemToolkit.h"
|
||||
|
||||
/// The amount of memory currently being used by this process, in bytes.
|
||||
/// it will try to report the resident set in RAM
|
||||
long SystemToolkit::memory_usage()
|
||||
{
|
||||
#if defined(LINUX)
|
||||
// Grabbing info directly from the /proc pseudo-filesystem. Reading from
|
||||
// /proc/self/statm gives info on your own process, as one line of
|
||||
// numbers that are: virtual mem program size, resident set size,
|
||||
// shared pages, text/code, data/stack, library, dirty pages. The
|
||||
// mem sizes should all be multiplied by the page size.
|
||||
size_t size = 0;
|
||||
FILE *file = fopen("/proc/self/statm", "r");
|
||||
if (file) {
|
||||
unsigned long m = 0;
|
||||
fscanf (file, "%lu", &m); // virtual mem program size,
|
||||
fscanf (file, "%lu", &m); // resident set size,
|
||||
fclose (file);
|
||||
size = (size_t)m * getpagesize();
|
||||
}
|
||||
return (long)size;
|
||||
|
||||
#elif defined(APPLE)
|
||||
// Inspired from
|
||||
// http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html
|
||||
struct task_basic_info t_info;
|
||||
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
|
||||
task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
|
||||
return t_info.resident_size;
|
||||
|
||||
#elif defined(WIN32)
|
||||
// According to MSDN...
|
||||
PROCESS_MEMORY_COUNTERS counters;
|
||||
if (GetProcessMemoryInfo (GetCurrentProcess(), &counters, sizeof (counters)))
|
||||
return counters.PagefileUsage;
|
||||
else return 0;
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
long SystemToolkit::memory_max_usage() {
|
||||
|
||||
struct rusage r_usage;
|
||||
getrusage(RUSAGE_SELF,&r_usage);
|
||||
return r_usage.ru_maxrss;
|
||||
// return r_usage.ru_isrss;
|
||||
}
|
||||
|
||||
string SystemToolkit::byte_to_string(long b)
|
||||
{
|
||||
double numbytes = static_cast<double>(b);
|
||||
ostringstream oss;
|
||||
|
||||
std::list<std::string> list = {" Bytes", " KB", " MB", " GB", " TB"};
|
||||
std::list<std::string>::iterator i = list.begin();
|
||||
|
||||
while(numbytes >= 1024.0 && i != list.end())
|
||||
{
|
||||
i++;
|
||||
numbytes /= 1024.0;
|
||||
}
|
||||
oss << std::fixed << std::setprecision(2) << numbytes << *i;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
string SystemToolkit::date_time_string()
|
||||
{
|
||||
chrono::system_clock::time_point now = chrono::system_clock::now();
|
||||
time_t t = chrono::system_clock::to_time_t(now);
|
||||
tm* datetime = localtime(&t);
|
||||
|
||||
auto duration = now.time_since_epoch();
|
||||
auto millis = chrono::duration_cast<chrono::milliseconds>(duration).count() % 1000;
|
||||
|
||||
ostringstream oss;
|
||||
oss << setw(4) << setfill('0') << to_string(datetime->tm_year + 1900);
|
||||
oss << setw(2) << setfill('0') << to_string(datetime->tm_mon + 1);
|
||||
oss << setw(2) << setfill('0') << to_string(datetime->tm_mday );
|
||||
oss << setw(2) << setfill('0') << to_string(datetime->tm_hour );
|
||||
oss << setw(2) << setfill('0') << to_string(datetime->tm_min );
|
||||
oss << setw(2) << setfill('0') << to_string(datetime->tm_sec );
|
||||
oss << setw(3) << setfill('0') << to_string(millis);
|
||||
|
||||
// fixed length string (17 chars) YYYYMMDDHHmmssiii
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
string SystemToolkit::filename(const string& path)
|
||||
{
|
||||
return path.substr(path.find_last_of(PATH_SEP) + 1);
|
||||
}
|
||||
|
||||
string SystemToolkit::base_filename(const string& path)
|
||||
{
|
||||
string basefilename = SystemToolkit::filename(path);
|
||||
const size_t period_idx = basefilename.rfind('.');
|
||||
if (string::npos != period_idx)
|
||||
{
|
||||
basefilename.erase(period_idx);
|
||||
}
|
||||
return basefilename;
|
||||
}
|
||||
|
||||
string SystemToolkit::path_filename(const string& path)
|
||||
{
|
||||
return path.substr(0, path.find_last_of(PATH_SEP) + 1);
|
||||
}
|
||||
|
||||
string SystemToolkit::trunc_filename(const string& path, int lenght)
|
||||
{
|
||||
string trunc = path;
|
||||
int l = path.size();
|
||||
if ( l > lenght ) {
|
||||
trunc = string("...") + path.substr( l - lenght + 3 );
|
||||
}
|
||||
return trunc;
|
||||
}
|
||||
|
||||
string SystemToolkit::extension_filename(const string& filename)
|
||||
{
|
||||
string ext = filename.substr(filename.find_last_of(".") + 1);
|
||||
return ext;
|
||||
}
|
||||
|
||||
std::string SystemToolkit::home_path()
|
||||
{
|
||||
// 1. find home
|
||||
char *mHomePath;
|
||||
// try the system user info
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd)
|
||||
mHomePath = pwd->pw_dir;
|
||||
else
|
||||
// try the $HOME environment variable
|
||||
mHomePath = getenv("HOME");
|
||||
|
||||
return string(mHomePath) + PATH_SEP;
|
||||
}
|
||||
|
||||
|
||||
std::string SystemToolkit::cwd_path()
|
||||
{
|
||||
char mCwdPath[PATH_MAX];
|
||||
|
||||
if (getcwd(mCwdPath, sizeof(mCwdPath)) != NULL)
|
||||
return string(mCwdPath) + PATH_SEP;
|
||||
else
|
||||
return string();
|
||||
}
|
||||
|
||||
std::string SystemToolkit::username()
|
||||
{
|
||||
// 1. find home
|
||||
char *user;
|
||||
// try the system user info
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd)
|
||||
user = pwd->pw_name;
|
||||
else
|
||||
// try the $USER environment variable
|
||||
user = getenv("USER");
|
||||
|
||||
return string(user);
|
||||
}
|
||||
|
||||
bool SystemToolkit::create_directory(const string& path)
|
||||
{
|
||||
return !mkdir(path.c_str(), 0755) || errno == EEXIST;
|
||||
|
||||
// TODO : verify WIN32 implementation
|
||||
}
|
||||
|
||||
string SystemToolkit::settings_path()
|
||||
{
|
||||
string home(home_path());
|
||||
|
||||
// 2. try to access user settings folder
|
||||
string settingspath = home + PATH_SETTINGS;
|
||||
if (SystemToolkit::file_exists(settingspath)) {
|
||||
// good, we have a place to put the settings file
|
||||
// settings should be in 'vmix' subfolder
|
||||
settingspath += APP_NAME;
|
||||
|
||||
// 3. create the vmix subfolder in settings folder if not existing already
|
||||
if ( !SystemToolkit::file_exists(settingspath)) {
|
||||
if ( !create_directory(settingspath) )
|
||||
// fallback to home if settings path cannot be created
|
||||
settingspath = home;
|
||||
}
|
||||
|
||||
return settingspath;
|
||||
}
|
||||
else {
|
||||
// fallback to home if settings path does not exists
|
||||
return home;
|
||||
}
|
||||
}
|
||||
|
||||
string SystemToolkit::full_filename(const std::string& path, const string &filename)
|
||||
{
|
||||
string fullfilename = path;
|
||||
fullfilename += PATH_SEP;
|
||||
fullfilename += filename;
|
||||
|
||||
return fullfilename;
|
||||
}
|
||||
|
||||
bool SystemToolkit::file_exists(const string& path)
|
||||
{
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
return access(path.c_str(), R_OK) == 0;
|
||||
|
||||
// TODO : WIN32 implementation
|
||||
}
|
||||
|
||||
|
||||
// tests if dir is a directory and return its path, empty string otherwise
|
||||
std::string SystemToolkit::path_directory(const std::string& path)
|
||||
{
|
||||
string directorypath = "";
|
||||
|
||||
DIR *dir;
|
||||
if ((dir = opendir (path.c_str())) != NULL) {
|
||||
directorypath = path + PATH_SEP;
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
return directorypath;
|
||||
}
|
||||
|
||||
list<string> SystemToolkit::list_directory(const string& path, const string& filter)
|
||||
{
|
||||
list<string> ls;
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
if ((dir = opendir (path.c_str())) != NULL) {
|
||||
// list all the files and directories within directory
|
||||
while ((ent = readdir (dir)) != NULL) {
|
||||
if ( ent->d_type == DT_REG)
|
||||
{
|
||||
string filename = string(ent->d_name);
|
||||
if ( extension_filename(filename) == filter)
|
||||
ls.push_back( full_filename(path, filename) );
|
||||
}
|
||||
}
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
void SystemToolkit::open(const string& url)
|
||||
{
|
||||
#ifdef WIN32
|
||||
ShellExecuteA( nullptr, nullptr, url.c_str(), nullptr, nullptr, 0 );
|
||||
#elif defined APPLE
|
||||
char buf[2048];
|
||||
sprintf( buf, "open '%s'", url.c_str() );
|
||||
system( buf );
|
||||
#else
|
||||
char buf[2048];
|
||||
sprintf( buf, "xdg-open '%s'", url.c_str() );
|
||||
int r = system( buf );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
#ifndef __UI_MANAGER_H_
|
||||
#define __UI_MANAGER_H_
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#define NAV_COUNT 68
|
||||
#define NAV_MAX 64
|
||||
#define NAV_NEW 65
|
||||
#define NAV_MENU 66
|
||||
#define NAV_TRANS 67
|
||||
|
||||
struct ImVec2;
|
||||
class Source;
|
||||
class MediaPlayer;
|
||||
|
||||
class SourcePreview {
|
||||
|
||||
Source *source_;
|
||||
std::string label_;
|
||||
|
||||
public:
|
||||
SourcePreview();
|
||||
|
||||
void setSource(Source *s = nullptr, std::string label = "");
|
||||
Source *getSource();
|
||||
|
||||
void Render(float width, bool controlbutton = false);
|
||||
inline bool ready() const { return source_ != nullptr; }
|
||||
};
|
||||
|
||||
class Navigator
|
||||
{
|
||||
// geometry left bar & pannel
|
||||
float width_;
|
||||
float height_;
|
||||
float pannel_width_;
|
||||
float sourcelist_height_;
|
||||
float padding_width_;
|
||||
|
||||
// behavior pannel
|
||||
bool pannel_visible_;
|
||||
bool selected_button[NAV_COUNT];
|
||||
void clearButtonSelection();
|
||||
void applyButtonSelection(int index);
|
||||
|
||||
// side pannels
|
||||
void RenderSourcePannel(Source *s);
|
||||
void RenderMainPannel();
|
||||
void RenderTransitionPannel();
|
||||
void RenderNewPannel();
|
||||
int new_source_type_;
|
||||
char file_browser_path_[2048];
|
||||
|
||||
SourcePreview new_source_preview_;
|
||||
|
||||
public:
|
||||
Navigator();
|
||||
|
||||
bool pannelVisible() { return pannel_visible_; }
|
||||
void hidePannel();
|
||||
void showPannelSource(int index);
|
||||
void togglePannelMenu();
|
||||
void togglePannelNew();
|
||||
|
||||
|
||||
void Render();
|
||||
};
|
||||
|
||||
class ToolBox
|
||||
{
|
||||
bool show_demo_window;
|
||||
bool show_icons_window;
|
||||
|
||||
public:
|
||||
ToolBox();
|
||||
|
||||
void Render();
|
||||
};
|
||||
|
||||
|
||||
class MediaController
|
||||
{
|
||||
MediaPlayer *mp_;
|
||||
std::string current_;
|
||||
bool follow_active_source_;
|
||||
bool media_playing_mode_;
|
||||
bool slider_pressed_;
|
||||
|
||||
public:
|
||||
MediaController();
|
||||
|
||||
void setMediaPlayer(MediaPlayer *mp = nullptr);
|
||||
void followCurrentSource();
|
||||
|
||||
void Render();
|
||||
};
|
||||
|
||||
class UserInterface
|
||||
{
|
||||
friend class Navigator;
|
||||
Navigator navigator;
|
||||
ToolBox toolbox;
|
||||
MediaController mediacontrol;
|
||||
|
||||
bool keyboard_modifier_active;
|
||||
bool show_vimix_config;
|
||||
bool show_imgui_about;
|
||||
bool show_gst_about;
|
||||
bool show_opengl_about;
|
||||
unsigned int screenshot_step;
|
||||
|
||||
|
||||
// typedef enum {
|
||||
// FILE_DIALOG_INACTIVE = 0,
|
||||
// FILE_DIALOG_ACTIVE,
|
||||
// FILE_DIALOG_FINISHED
|
||||
// } FileDialogStatus;
|
||||
// FileDialogStatus filestatus_;
|
||||
// std::string filename_;
|
||||
// void startOpenFileDialog();
|
||||
|
||||
// Private Constructor
|
||||
UserInterface();
|
||||
UserInterface(UserInterface const& copy); // Not Implemented
|
||||
UserInterface& operator=(UserInterface const& copy); // Not Implemented
|
||||
|
||||
public:
|
||||
|
||||
static UserInterface& manager()
|
||||
{
|
||||
// The only instance
|
||||
static UserInterface _instance;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
// pre-loop initialization
|
||||
bool Init();
|
||||
// loop update start new frame
|
||||
void NewFrame();
|
||||
// loop update rendering
|
||||
void Render();
|
||||
// Post-loop termination
|
||||
void Terminate();
|
||||
|
||||
// status querries
|
||||
inline bool keyboardModifier() { return keyboard_modifier_active; }
|
||||
|
||||
void StartScreenshot();
|
||||
void showPannel(int id = 0);
|
||||
|
||||
void showMediaPlayer(MediaPlayer *mp);
|
||||
|
||||
// TODO implement the shader editor
|
||||
std::string currentTextEdit;
|
||||
void fillShaderEditor(std::string text);
|
||||
|
||||
protected:
|
||||
|
||||
void showMenuFile();
|
||||
|
||||
void RenderPreview();
|
||||
void RenderShaderEditor();
|
||||
void handleKeyboard();
|
||||
void handleMouse();
|
||||
void handleScreenshot();
|
||||
};
|
||||
|
||||
#endif /* #define __UI_MANAGER_H_ */
|
||||
|
||||
195
View.h
@@ -1,195 +0,0 @@
|
||||
#ifndef VIEW_H
|
||||
#define VIEW_H
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Scene.h"
|
||||
#include "FrameBuffer.h"
|
||||
class Source;
|
||||
class SessionSource;
|
||||
class Surface;
|
||||
|
||||
class View
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum {RENDERING = 0, MIXING=1, GEOMETRY=2, LAYER=3, TRANSITION=4, INVALID=5 } Mode;
|
||||
|
||||
View(Mode m);
|
||||
virtual ~View() {}
|
||||
|
||||
inline Mode mode() const { return mode_; }
|
||||
|
||||
virtual void update (float dt);
|
||||
virtual void draw ();
|
||||
|
||||
virtual void zoom (float) {}
|
||||
virtual void recenter();
|
||||
virtual void centerSource(Source *) {}
|
||||
|
||||
typedef enum {
|
||||
Cursor_Arrow = 0,
|
||||
Cursor_TextInput,
|
||||
Cursor_ResizeAll,
|
||||
Cursor_ResizeNS,
|
||||
Cursor_ResizeEW,
|
||||
Cursor_ResizeNESW,
|
||||
Cursor_ResizeNWSE,
|
||||
Cursor_Hand,
|
||||
Cursor_NotAllowed
|
||||
} CursorType;
|
||||
|
||||
typedef struct Cursor {
|
||||
CursorType type;
|
||||
std::string info;
|
||||
Cursor() { type = Cursor_Arrow; info = "";}
|
||||
Cursor(CursorType t, std::string i = "") { type = t; info = i;}
|
||||
} Cursor;
|
||||
|
||||
// picking of nodes in a view provided a point coordinates in screen coordinates
|
||||
virtual std::pair<Node *, glm::vec2> pick(glm::vec2);
|
||||
|
||||
// select sources provided a start and end selection points in screen coordinates
|
||||
virtual void select(glm::vec2, glm::vec2);
|
||||
virtual void selectAll();
|
||||
|
||||
// drag the view provided a start and an end point in screen coordinates
|
||||
virtual Cursor drag (glm::vec2, glm::vec2);
|
||||
|
||||
// grab a source provided a start and an end point in screen coordinates and the picking point
|
||||
virtual void storeStatus();
|
||||
virtual Cursor grab (Source*, glm::vec2, glm::vec2, std::pair<Node *, glm::vec2>) {
|
||||
return Cursor();
|
||||
}
|
||||
|
||||
// test mouse over provided a point in screen coordinates and the picking point
|
||||
virtual Cursor over (Source*, glm::vec2, std::pair<Node *, glm::vec2>) {
|
||||
return Cursor();
|
||||
}
|
||||
|
||||
// accessible scene
|
||||
Scene scene;
|
||||
|
||||
// reordering scene when necessary
|
||||
static bool need_deep_update_;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void restoreSettings();
|
||||
virtual void saveSettings();
|
||||
|
||||
Mode mode_;
|
||||
};
|
||||
|
||||
|
||||
class MixingView : public View
|
||||
{
|
||||
public:
|
||||
MixingView();
|
||||
|
||||
void draw () override;
|
||||
void update (float dt) override;
|
||||
void zoom (float factor) override;
|
||||
void centerSource(Source *) override;
|
||||
void selectAll() override;
|
||||
|
||||
std::pair<Node *, glm::vec2> pick(glm::vec2) override;
|
||||
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2>) override;
|
||||
Cursor drag (glm::vec2, glm::vec2) override;
|
||||
|
||||
void setAlpha (Source *s);
|
||||
inline float limboScale() { return limbo_scale_; }
|
||||
|
||||
private:
|
||||
uint textureMixingQuadratic();
|
||||
float limbo_scale_;
|
||||
|
||||
Group *slider_root_;
|
||||
class Disk *slider_;
|
||||
class Disk *button_white_;
|
||||
class Disk *button_black_;
|
||||
class Mesh *mixingCircle_;
|
||||
};
|
||||
|
||||
class RenderView : public View
|
||||
{
|
||||
FrameBuffer *intermediate_buffer_;
|
||||
FrameBuffer *frame_buffer_;
|
||||
Surface *fading_overlay_;
|
||||
|
||||
public:
|
||||
RenderView ();
|
||||
~RenderView ();
|
||||
|
||||
void draw () override;
|
||||
|
||||
void setResolution (glm::vec3 resolution = glm::vec3(0.f));
|
||||
glm::vec3 resolution() const { return frame_buffer_->resolution(); }
|
||||
|
||||
void setFading(float f = 0.f);
|
||||
float fading() const;
|
||||
|
||||
inline FrameBuffer *frame () const { return frame_buffer_; }
|
||||
};
|
||||
|
||||
class GeometryView : public View
|
||||
{
|
||||
public:
|
||||
GeometryView();
|
||||
|
||||
void draw () override;
|
||||
void update (float dt) override;
|
||||
void zoom (float factor) override;
|
||||
|
||||
std::pair<Node *, glm::vec2> pick(glm::vec2 P) override;
|
||||
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
|
||||
Cursor over (Source *s, glm::vec2 pos, std::pair<Node *, glm::vec2> pick) override;
|
||||
Cursor drag (glm::vec2, glm::vec2) override;
|
||||
|
||||
};
|
||||
|
||||
class LayerView : public View
|
||||
{
|
||||
public:
|
||||
LayerView();
|
||||
|
||||
void update (float dt) override;
|
||||
void zoom (float factor) override;
|
||||
|
||||
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
|
||||
Cursor drag (glm::vec2, glm::vec2) override;
|
||||
|
||||
float setDepth (Source *, float d = -1.f);
|
||||
|
||||
private:
|
||||
float aspect_ratio;
|
||||
};
|
||||
|
||||
class TransitionView : public View
|
||||
{
|
||||
public:
|
||||
TransitionView();
|
||||
|
||||
void draw () override;
|
||||
void update (float dt) override;
|
||||
void zoom (float factor) override;
|
||||
void selectAll() override;
|
||||
|
||||
std::pair<Node *, glm::vec2> pick(glm::vec2 P) override;
|
||||
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
|
||||
Cursor drag (glm::vec2, glm::vec2) override;
|
||||
|
||||
void attach(SessionSource *ts);
|
||||
class Session *detach();
|
||||
void play(bool open);
|
||||
|
||||
private:
|
||||
class Surface *output_surface_;
|
||||
class Mesh *mark_100ms_, *mark_1s_;
|
||||
Switch *gradient_;
|
||||
SessionSource *transition_source_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // VIEW_H
|
||||
71
Visitor.h
@@ -1,71 +0,0 @@
|
||||
#ifndef VISITOR_H
|
||||
#define VISITOR_H
|
||||
|
||||
#include <string>
|
||||
|
||||
// Forward declare different kind of Node
|
||||
class Node;
|
||||
class Group;
|
||||
class Switch;
|
||||
class Primitive;
|
||||
class Scene;
|
||||
class Surface;
|
||||
class ImageSurface;
|
||||
class MediaSurface;
|
||||
class FrameBufferSurface;
|
||||
class LineStrip;
|
||||
class LineSquare;
|
||||
class LineCircle;
|
||||
class Mesh;
|
||||
class Frame;
|
||||
class Handles;
|
||||
class Disk;
|
||||
class MediaPlayer;
|
||||
class Shader;
|
||||
class ImageShader;
|
||||
class ImageProcessingShader;
|
||||
class Source;
|
||||
class MediaSource;
|
||||
class SessionSource;
|
||||
class RenderSource;
|
||||
class CloneSource;
|
||||
|
||||
// Declares the interface for the visitors
|
||||
class Visitor {
|
||||
|
||||
public:
|
||||
// Need to declare overloads for basic kind of Nodes to visit
|
||||
virtual void visit (Scene&) = 0;
|
||||
virtual void visit (Node&) = 0;
|
||||
virtual void visit (Primitive&) = 0;
|
||||
virtual void visit (Group&) = 0;
|
||||
virtual void visit (Switch&) = 0;
|
||||
|
||||
// not mandatory for all others
|
||||
virtual void visit (Surface&) {}
|
||||
virtual void visit (ImageSurface&) {}
|
||||
virtual void visit (MediaSurface&) {}
|
||||
virtual void visit (FrameBufferSurface&) {}
|
||||
virtual void visit (LineStrip&) {}
|
||||
virtual void visit (LineSquare&) {}
|
||||
virtual void visit (LineCircle&) {}
|
||||
virtual void visit (Mesh&) {}
|
||||
virtual void visit (Frame&) {}
|
||||
virtual void visit (Handles&) {}
|
||||
virtual void visit (Disk&) {}
|
||||
virtual void visit (MediaPlayer&) {}
|
||||
virtual void visit (Shader&) {}
|
||||
virtual void visit (ImageShader&) {}
|
||||
virtual void visit (ImageProcessingShader&) {}
|
||||
|
||||
// utility
|
||||
virtual void visit (Source&) {}
|
||||
virtual void visit (MediaSource&) {}
|
||||
virtual void visit (SessionSource&) {}
|
||||
virtual void visit (RenderSource&) {}
|
||||
virtual void visit (CloneSource&) {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // VISITOR_H
|
||||
1
_config.yml
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-midnight
|
||||
41
cmake/modules/BundleInstall.cmake.in
Normal file
@@ -0,0 +1,41 @@
|
||||
set(BUNDLE_NAME @BUNDLE_NAME@)
|
||||
set(BUNDLE_LIBS_DIR @BUNDLE_LIBS_DIR@)
|
||||
set(BUNDLE_DIRS @BUNDLE_DIRS@)
|
||||
set(APPLE_CODESIGN_IDENTITY @APPLE_CODESIGN_IDENTITY@)
|
||||
set(APPLE_CODESIGN_ENTITLEMENTS @APPLE_CODESIGN_ENTITLEMENTS@)
|
||||
|
||||
set(BUNDLE_PATH "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}")
|
||||
|
||||
include(BundleUtilities)
|
||||
|
||||
#fixup_bundle tries to copy system libraries without this. Wtf?
|
||||
function(gp_resolved_file_type_override file type)
|
||||
if(file MATCHES "^(/usr/lib)")
|
||||
set(type "system" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
file(GLOB_RECURSE BUNDLE_LIBS "${CMAKE_INSTALL_PREFIX}/${BUNDLE_LIBS_DIR}/*.dylib")
|
||||
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
fixup_bundle("${BUNDLE_PATH}" "${BUNDLE_LIBS}" "${BUNDLE_DIRS}")
|
||||
|
||||
if(DEFINED APPLE_CODESIGN_IDENTITY AND DEFINED APPLE_CODESIGN_ENTITLEMENTS)
|
||||
# execute_process(COMMAND
|
||||
# codesign --verbose=4 --deep --force --options runtime
|
||||
# --entitlements "${APPLE_CODESIGN_ENTITLEMENTS}"
|
||||
# --sign "${APPLE_CODESIGN_IDENTITY}"
|
||||
# "${BUNDLE_NAME}"
|
||||
# )
|
||||
foreach(PATH_TO_SIGN IN LISTS BUNDLE_LIBS BUNDLE_PATH)
|
||||
execute_process(COMMAND
|
||||
codesign --verbose=4 --deep --force
|
||||
--entitlements "${APPLE_CODESIGN_ENTITLEMENTS}"
|
||||
--sign "${APPLE_CODESIGN_IDENTITY}"
|
||||
"${PATH_TO_SIGN}"
|
||||
)
|
||||
endforeach()
|
||||
else()
|
||||
message(STATUS "Not signing bundle. Specify -DAPPLE_CODESIGN_IDENTITY and -DAPPLE_CODESIGN_ENTITLEMENTS to cmake before running cpack to sign")
|
||||
endif()
|
||||
|
||||
@@ -34,7 +34,7 @@ endif()
|
||||
|
||||
set(_version 2.0.0)
|
||||
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
include(CMakeParseArguments)
|
||||
|
||||
if(COMMAND cmrc_add_resource_library)
|
||||
@@ -77,6 +77,10 @@ set(hpp_content [==[
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
#if !(defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) || defined(CMRC_NO_EXCEPTIONS))
|
||||
#define CMRC_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
namespace cmrc { namespace detail { struct dummy; } }
|
||||
|
||||
#define CMRC_DECLARE(libid) \
|
||||
@@ -101,7 +105,7 @@ public:
|
||||
iterator cbegin() const noexcept { return _begin; }
|
||||
iterator end() const noexcept { return _end; }
|
||||
iterator cend() const noexcept { return _end; }
|
||||
std::size_t size() const { return std::distance(begin(), end()); }
|
||||
std::size_t size() const { return static_cast<std::size_t>(std::distance(begin(), end())); }
|
||||
|
||||
file() = default;
|
||||
file(iterator beg, iterator end) noexcept : _begin(beg), _end(end) {}
|
||||
@@ -243,16 +247,16 @@ public:
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
iterator operator++() noexcept {
|
||||
iterator& operator++() noexcept {
|
||||
++_base_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) noexcept {
|
||||
auto cp = *this;
|
||||
++_base_iter;
|
||||
return cp;
|
||||
}
|
||||
|
||||
iterator& operator++(int) noexcept {
|
||||
++_base_iter;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using const_iterator = iterator;
|
||||
@@ -275,7 +279,7 @@ inline std::string normalize_path(std::string path) {
|
||||
}
|
||||
auto off = path.npos;
|
||||
while ((off = path.find("//")) != path.npos) {
|
||||
path.erase(path.begin() + off);
|
||||
path.erase(path.begin() + static_cast<std::string::difference_type>(off));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
@@ -339,7 +343,12 @@ public:
|
||||
file open(const std::string& path) const {
|
||||
auto entry_ptr = _get(path);
|
||||
if (!entry_ptr || !entry_ptr->is_file()) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
|
||||
#endif
|
||||
}
|
||||
auto& dat = entry_ptr->as_file();
|
||||
return file{dat.begin_ptr, dat.end_ptr};
|
||||
@@ -362,10 +371,20 @@ public:
|
||||
directory_iterator iterate_directory(const std::string& path) const {
|
||||
auto entry_ptr = _get(path);
|
||||
if (!entry_ptr) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
|
||||
#endif
|
||||
}
|
||||
if (!entry_ptr->is_directory()) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error not a directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::not_a_directory), path);
|
||||
#endif
|
||||
}
|
||||
return entry_ptr->as_directory().begin();
|
||||
}
|
||||
@@ -387,14 +406,14 @@ endif()
|
||||
file(GENERATE OUTPUT "${cmrc_hpp}" CONTENT "${hpp_content}" CONDITION ${_generate})
|
||||
|
||||
add_library(cmrc-base INTERFACE)
|
||||
target_include_directories(cmrc-base INTERFACE "${CMRC_INCLUDE_DIR}")
|
||||
target_include_directories(cmrc-base INTERFACE $<BUILD_INTERFACE:${CMRC_INCLUDE_DIR}>)
|
||||
# Signal a basic C++11 feature to require C++11.
|
||||
target_compile_features(cmrc-base INTERFACE cxx_nullptr)
|
||||
set_property(TARGET cmrc-base PROPERTY INTERFACE_CXX_EXTENSIONS OFF)
|
||||
add_library(cmrc::base ALIAS cmrc-base)
|
||||
|
||||
function(cmrc_add_resource_library name)
|
||||
set(args ALIAS NAMESPACE)
|
||||
set(args ALIAS NAMESPACE TYPE)
|
||||
cmake_parse_arguments(ARG "" "${args}" "" "${ARGN}")
|
||||
# Generate the identifier for the resource library's namespace
|
||||
set(ns_re "[a-zA-Z_][a-zA-Z0-9_]*")
|
||||
@@ -410,6 +429,14 @@ function(cmrc_add_resource_library name)
|
||||
endif()
|
||||
endif()
|
||||
set(libname "${name}")
|
||||
# Check that type is either "STATIC" or "OBJECT", or default to "STATIC" if
|
||||
# not set
|
||||
if(NOT DEFINED ARG_TYPE)
|
||||
set(ARG_TYPE STATIC)
|
||||
elseif(NOT "${ARG_TYPE}" MATCHES "^(STATIC|OBJECT)$")
|
||||
message(SEND_ERROR "${ARG_TYPE} is not a valid TYPE (STATIC and OBJECT are acceptable)")
|
||||
set(ARG_TYPE STATIC)
|
||||
endif()
|
||||
# Generate a library with the compiled in character arrays.
|
||||
string(CONFIGURE [=[
|
||||
#include <cmrc/cmrc.hpp>
|
||||
@@ -468,7 +495,7 @@ function(cmrc_add_resource_library name)
|
||||
# Generate the actual static library. Each source file is just a single file
|
||||
# with a character array compiled in containing the contents of the
|
||||
# corresponding resource file.
|
||||
add_library(${name} STATIC ${libcpp})
|
||||
add_library(${name} ${ARG_TYPE} ${libcpp})
|
||||
set_property(TARGET ${name} PROPERTY CMRC_LIBDIR "${libdir}")
|
||||
set_property(TARGET ${name} PROPERTY CMRC_NAMESPACE "${ARG_NAMESPACE}")
|
||||
target_link_libraries(${name} PUBLIC cmrc::base)
|
||||
@@ -558,7 +585,7 @@ function(cmrc_add_resources name)
|
||||
endif()
|
||||
get_filename_component(dirpath "${ARG_PREFIX}${relpath}" DIRECTORY)
|
||||
_cmrc_register_dirs("${name}" "${dirpath}")
|
||||
get_filename_component(abs_out "${libdir}/intermediate/${relpath}.cpp" ABSOLUTE)
|
||||
get_filename_component(abs_out "${libdir}/intermediate/${ARG_PREFIX}${relpath}.cpp" ABSOLUTE)
|
||||
# Generate a symbol name relpath the file's character array
|
||||
_cm_encode_fpath(sym "${relpath}")
|
||||
# Get the symbol name for the parent directory
|
||||
|
||||
@@ -33,9 +33,10 @@ find_package(PkgConfig)
|
||||
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PKG_GSTREAMER gstreamer-${GSTREAMER_ABI_VERSION})
|
||||
exec_program(${PKG_CONFIG_EXECUTABLE}
|
||||
ARGS --variable pluginsdir gstreamer-${GSTREAMER_ABI_VERSION}
|
||||
OUTPUT_VARIABLE PKG_GSTREAMER_PLUGIN_DIR)
|
||||
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
|
||||
--variable pluginsdir gstreamer-${GSTREAMER_ABI_VERSION}
|
||||
OUTPUT_VARIABLE PKG_GSTREAMER_PLUGIN_DIR_TMP)
|
||||
string(STRIP ${PKG_GSTREAMER_PLUGIN_DIR_TMP} PKG_GSTREAMER_PLUGIN_DIR)
|
||||
endif()
|
||||
|
||||
find_library(GSTREAMER_LIBRARY
|
||||
|
||||
76
cmake/modules/FindGStreamerPluginsBad.cmake
Normal file
@@ -0,0 +1,76 @@
|
||||
# - Try to find gst-plugins-base
|
||||
# Once done this will define
|
||||
#
|
||||
# GSTREAMER_PLUGINS_BASE_FOUND - system has gst-plugins-base
|
||||
#
|
||||
# And for all the plugin libraries specified in the COMPONENTS
|
||||
# of find_package, this module will define:
|
||||
#
|
||||
# GSTREAMER_<plugin_lib>_LIBRARY_FOUND - system has <plugin_lib>
|
||||
# GSTREAMER_<plugin_lib>_LIBRARY - the <plugin_lib> library
|
||||
# GSTREAMER_<plugin_lib>_INCLUDE_DIR - the <plugin_lib> include directory
|
||||
#
|
||||
# Copyright (c) 2010, Collabora Ltd.
|
||||
# @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
set(GSTREAMER_ABI_VERSION "1.0")
|
||||
|
||||
|
||||
# Find the pkg-config file for doing the version check
|
||||
find_package(PkgConfig)
|
||||
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PKG_GSTREAMER_PLUGINS_BAD gstreamer-plugins-bad-${GSTREAMER_ABI_VERSION})
|
||||
endif()
|
||||
|
||||
|
||||
# Find the plugin libraries
|
||||
include(MacroFindGStreamerLibrary)
|
||||
|
||||
macro(_find_gst_plugins_bad_component _name _header)
|
||||
find_gstreamer_library(${_name} ${_header} ${GSTREAMER_ABI_VERSION})
|
||||
set(_GSTREAMER_PLUGINS_BAD_EXTRA_VARIABLES ${_GSTREAMER_PLUGINS_BAD_EXTRA_VARIABLES}
|
||||
GSTREAMER_${_name}_LIBRARY GSTREAMER_${_name}_INCLUDE_DIR)
|
||||
endmacro()
|
||||
|
||||
foreach(_component ${GStreamerPluginsBad_FIND_COMPONENTS})
|
||||
if (${_component} STREQUAL "player")
|
||||
_find_gst_plugins_bad_component(PLAYER gstplayer.h)
|
||||
elseif (${_component} STREQUAL "webrtc")
|
||||
_find_gst_plugins_bad_component(WEBRTC webrtc.h)
|
||||
elseif (${_component} STREQUAL "srtsrc")
|
||||
_find_gst_plugins_bad_component(SRTSRC mpegts.h)
|
||||
else()
|
||||
message (AUTHOR_WARNING "FindGStreamerPluginBad.cmake: Invalid component \"${_component}\" was specified")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
get_filename_component(_GSTREAMER_BAD_LIB_DIR ${GSTREAMER_PLAYER_LIBRARY} PATH)
|
||||
set(PKG_GSTREAMER_BAD_PLUGIN_DIR ${_GSTREAMER_BAD_LIB_DIR}/gstreamer-${GSTREAMER_ABI_VERSION})
|
||||
|
||||
# Version check
|
||||
if (GStreamerPluginsBad_FIND_VERSION)
|
||||
if (PKG_GSTREAMER_PLUGINS_BAD_FOUND)
|
||||
if("${PKG_GSTREAMER_PLUGINS_BAD_VERSION}" VERSION_LESS "${GStreamerPluginsBad_FIND_VERSION}")
|
||||
message(STATUS "Found gst-plugins-base version ${PKG_GSTREAMER_PLUGINS_BAD_VERSION}, but at least version ${GStreamerPluginsBad_FIND_VERSION} is required")
|
||||
set(GSTREAMER_PLUGINS_BAD_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(GSTREAMER_PLUGINS_BAD_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
else()
|
||||
# We can't make any version checks without pkg-config, just assume version is compatible and hope...
|
||||
set(GSTREAMER_PLUGINS_BAD_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
else()
|
||||
# No version constrain was specified, thus we consider the version compatible
|
||||
set(GSTREAMER_PLUGINS_BAD_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GStreamerPluginsBad DEFAULT_MSG
|
||||
GSTREAMER_PLUGINS_BAD_VERSION_COMPATIBLE
|
||||
${_GSTREAMER_PLUGINS_BAD_EXTRA_VARIABLES})
|
||||
@@ -64,6 +64,8 @@ foreach(_component ${GStreamerPluginsBase_FIND_COMPONENTS})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
get_filename_component(_GSTREAMER_BASE_LIB_DIR ${GSTREAMER_APP_LIBRARY} PATH)
|
||||
set(PKG_GSTREAMER_BASE_PLUGIN_DIR ${_GSTREAMER_BASE_LIB_DIR}/gstreamer-${GSTREAMER_ABI_VERSION})
|
||||
|
||||
# Version check
|
||||
if (GStreamerPluginsBase_FIND_VERSION)
|
||||
|
||||
147
cmake/modules/FindGTK.cmake
Normal file
@@ -0,0 +1,147 @@
|
||||
# - Try to find GTK+ 3.x or 4.x
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
# Copyright (C) 2013, 2015, 2020 Igalia S.L.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. 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.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS 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 HOLDER OR ITS
|
||||
# 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.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindGTK
|
||||
-------
|
||||
|
||||
Find GTK headers and libraries.
|
||||
|
||||
Optional Components
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``COMPONENTS`` (or ``OPTIONAL_COMPONENTS``) keyword can be passed to
|
||||
``find_package()``, the following GTK components can be searched for:
|
||||
|
||||
- ``unix-print``
|
||||
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``GTK::GTK``
|
||||
The GTK library, if found.
|
||||
``GTK::UnixPrint``
|
||||
The GTK unix-print library, if found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables in your project:
|
||||
|
||||
``GTK_FOUND``
|
||||
true if (the requested version of) GTK is available.
|
||||
``GTK_UNIX_PRINT_FOUND``
|
||||
true if the ``unix-print`` component is available.
|
||||
``GTK_4``
|
||||
whether GTK 4 was detected
|
||||
``GTK_3``
|
||||
whether GTK 3 was detected
|
||||
``GTK_VERSION``
|
||||
the version of GTK.
|
||||
``GTK_SUPPORTS_BROADWAY``
|
||||
true if the Broadway target is built into GTK.
|
||||
``GTK_SUPPORTS_QUARTZ``
|
||||
true if the Quartz target is built into GTK.
|
||||
``GTK_SUPPORTS_WAYLAND``
|
||||
true if the Wayland target is built into GTK.
|
||||
``GTK_SUPPORTS_WIN32``
|
||||
true if the Windows target is built into GTK.
|
||||
``GTK_SUPPORTS_X11``
|
||||
true if the X11 target is built into GTK.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
|
||||
if (GTK_FIND_VERSION VERSION_LESS 3.90)
|
||||
set(GTK_PC_MODULE "gtk+-3.0")
|
||||
set(GTK_PC_UNIX_PRINT_MODULE "gtk+-unix-print-3.0")
|
||||
set(GTK_4 FALSE)
|
||||
set(GTK_3 TRUE)
|
||||
else ()
|
||||
set(GTK_PC_MODULE "gtk4")
|
||||
set(GTK_PC_UNIX_PRINT_MODULE "gtk4-unix-print")
|
||||
set(GTK_4 TRUE)
|
||||
set(GTK_3 FALSE)
|
||||
endif ()
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(GTK IMPORTED_TARGET ${GTK_PC_MODULE})
|
||||
|
||||
set(GTK_VERSION_OK TRUE)
|
||||
if (GTK_VERSION)
|
||||
if (GTK_FIND_VERSION_EXACT)
|
||||
if (NOT("${GTK_FIND_VERSION}" VERSION_EQUAL "${GTK_VERSION}"))
|
||||
set(GTK_VERSION_OK FALSE)
|
||||
endif ()
|
||||
else ()
|
||||
if ("${GTK_VERSION}" VERSION_LESS "${GTK_FIND_VERSION}")
|
||||
set(GTK_VERSION_OK FALSE)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Set all the GTK_SUPPORTS_<target> variables to FALSE initially.
|
||||
foreach (gtk_target broadway quartz wayland win32 x11)
|
||||
string(TOUPPER "GTK_SUPPORTS_${gtk_target}" gtk_target)
|
||||
set(${gtk_target} FALSE)
|
||||
endforeach ()
|
||||
|
||||
if (GTK_VERSION AND GTK_VERSION_OK)
|
||||
# Fetch the "targets" variable and set GTK_SUPPORTS_<target>.
|
||||
pkg_get_variable(GTK_TARGETS ${GTK_PC_MODULE} targets)
|
||||
separate_arguments(GTK_TARGETS)
|
||||
foreach (gtk_target ${GTK_TARGETS})
|
||||
string(TOUPPER "GTK_SUPPORTS_${gtk_target}" gtk_target)
|
||||
set(${gtk_target} TRUE)
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
if (TARGET PkgConfig::GTK AND NOT TARGET GTK::GTK)
|
||||
add_library(GTK::GTK INTERFACE IMPORTED GLOBAL)
|
||||
set_property(TARGET GTK::GTK PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES PkgConfig::GTK
|
||||
)
|
||||
endif ()
|
||||
|
||||
# Try to find additional components
|
||||
foreach (gtk_component ${GTK_FIND_COMPONENTS})
|
||||
if (NOT "${gtk_component}" STREQUAL unix-print)
|
||||
message(FATAL_ERROR "Invalid component name: ${gtk_component}")
|
||||
endif ()
|
||||
pkg_check_modules(GTK_UNIX_PRINT IMPORTED_TARGET "${GTK_PC_UNIX_PRINT_MODULE}")
|
||||
if (GTK_FIND_REQUIRED_unix-print AND NOT GTK_UNIX_PRINT_FOUND)
|
||||
message(FATAL_ERROR "Component unix-print not found")
|
||||
endif ()
|
||||
if (TARGET PkgConfig::GTK_UNIX_PRINT AND NOT TARGET GTK::UnixPrint)
|
||||
add_library(GTK::UnixPrint INTERFACE IMPORTED GLOBAL)
|
||||
set_property(TARGET GTK::UnixPrint PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES PkgConfig::GTK_UNIX_PRINT)
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK DEFAULT_MSG GTK_VERSION GTK_VERSION_OK)
|
||||
103
defines.h
@@ -1,103 +0,0 @@
|
||||
#ifndef VMIX_DEFINES_H
|
||||
#define VMIX_DEFINES_H
|
||||
|
||||
#define APP_NAME "vimix"
|
||||
#define APP_TITLE " -- Video Live Mixer"
|
||||
#define APP_SETTINGS "vimix.xml"
|
||||
#define APP_VERSION_MAJOR 0
|
||||
#define APP_VERSION_MINOR 2
|
||||
#define XML_VERSION_MAJOR 0
|
||||
#define XML_VERSION_MINOR 1
|
||||
#define MAX_RECENT_HISTORY 20
|
||||
|
||||
#define MINI(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAXI(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
||||
#define ABS_DIFF(a, b) ( (a) < (b) ? (b - a) : (a - b) )
|
||||
#define SIGN(a) (((a) < 0) ? -1.0 : 1.0)
|
||||
#define SQUARE(a) ((a) * (a))
|
||||
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
|
||||
#define EPSILON 0.00001
|
||||
#define LOG100(val) (50.0/log(10.0)*log((float)val + 1.0))
|
||||
#define EXP100(val) (exp(log(10.0)/50.0*(float)(val))-1.0)
|
||||
#define EUCLIDEAN(P1, P2) sqrt((P1.x() - P2.x()) * (P1.x() - P2.x()) + (P1.y() - P2.y()) * (P1.y() - P2.y()))
|
||||
|
||||
#define SCENE_UNIT 5.f
|
||||
#define SCENE_DEPTH 12.f
|
||||
#define CIRCLE_SQUARE_DIST(x,y) ( (x*x + y*y) / (SCENE_UNIT * SCENE_UNIT * SCENE_UNIT * SCENE_UNIT) )
|
||||
#define MIN_SCALE 0.01f
|
||||
#define MAX_SCALE 10.f
|
||||
#define CLAMP_SCALE(x) SIGN(x) * CLAMP( ABS(x), MIN_SCALE, MAX_SCALE)
|
||||
#define MIXING_DEFAULT_SCALE 2.4f
|
||||
#define MIXING_MIN_SCALE 0.8f
|
||||
#define MIXING_MAX_SCALE 7.0f
|
||||
#define GEOMETRY_DEFAULT_SCALE 1.2f
|
||||
#define GEOMETRY_MIN_SCALE 0.2f
|
||||
#define GEOMETRY_MAX_SCALE 10.0f
|
||||
#define LAYER_DEFAULT_SCALE 0.8f
|
||||
#define LAYER_MIN_SCALE 0.4f
|
||||
#define LAYER_MAX_SCALE 1.7f
|
||||
#define TRANSITION_DEFAULT_SCALE 3.0f
|
||||
#define TRANSITION_MIN_DURATION 0.2f
|
||||
#define TRANSITION_MAX_DURATION 10.f
|
||||
|
||||
#define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " vimix"
|
||||
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Player"
|
||||
#define IMGUI_TITLE_TOOLBOX ICON_FA_WRENCH " Development Tools"
|
||||
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Shader Editor"
|
||||
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
||||
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
||||
#define IMGUI_LABEL_RECENT_FILES " Recent files"
|
||||
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
|
||||
#define IMGUI_NOTIFICATION_DURATION 1.5f
|
||||
#ifdef APPLE
|
||||
#define CTRL_MOD "Cmd+"
|
||||
#else
|
||||
#define CTRL_MOD "Ctrl+"
|
||||
#endif
|
||||
|
||||
#define COLOR_BGROUND 0.2f, 0.2f, 0.2f
|
||||
#define COLOR_NAVIGATOR 0.1f, 0.1f, 0.1f
|
||||
#define COLOR_DEFAULT_SOURCE 0.8f, 0.8f, 0.8f
|
||||
#define COLOR_HIGHLIGHT_SOURCE 1.f, 1.f, 1.f
|
||||
#define COLOR_TRANSITION_SOURCE 1.f, 0.5f, 1.f
|
||||
#define COLOR_TRANSITION_LINES 0.9f, 0.9f, 0.9f
|
||||
#define COLOR_FRAME 0.8f, 0.f, 0.8f
|
||||
#define COLOR_LIMBO_CIRCLE 0.16f, 0.16f, 0.16f
|
||||
#define COLOR_SLIDER_CIRCLE 0.11f, 0.11f, 0.11f
|
||||
|
||||
// from glmixer
|
||||
#define TEXTURE_REQUIRED_MAXIMUM 2048
|
||||
#define CATALOG_TEXTURE_HEIGHT 96
|
||||
#define SELECTBUFSIZE 512
|
||||
#define CIRCLE_SIZE 8.0
|
||||
#define DEFAULT_LIMBO_SIZE 1.5
|
||||
#define MIN_LIMBO_SIZE 1.1
|
||||
#define MAX_LIMBO_SIZE 3.0
|
||||
#define DEFAULT_ICON_SIZE 1.75
|
||||
#define MIN_ICON_SIZE 1.0
|
||||
#define MAX_ICON_SIZE 2.5
|
||||
#define MIN_DEPTH_LAYER 0.0
|
||||
#define MAX_DEPTH_LAYER 40.0
|
||||
#define DEPTH_EPSILON 0.1
|
||||
#define DEPTH_DEFAULT_SPACING 1.0
|
||||
#define BORDER_SIZE 0.4
|
||||
#define CENTER_SIZE 1.2
|
||||
#define PROPERTY_DECIMALS 8
|
||||
#define COLOR_SOURCE 230, 230, 0
|
||||
#define COLOR_SOURCE_STATIC 230, 40, 40
|
||||
#define COLOR_SELECTION 10, 210, 40
|
||||
#define COLOR_SELECTION_AREA 50, 210, 50
|
||||
#define COLOR_CIRCLE 210, 30, 210
|
||||
#define COLOR_CIRCLE_MOVE 230, 30, 230
|
||||
#define COLOR_DRAWINGS 180, 180, 180
|
||||
#define COLOR_LIMBO 35, 35, 35
|
||||
//#define COLOR_LIMBO_CIRCLE 210, 160, 210
|
||||
#define COLOR_FADING 25, 25, 25
|
||||
#define COLOR_FLASHING 250, 250, 250
|
||||
#define COLOR_FRAME_MOVE 230, 30, 230
|
||||
#define COLOR_CURSOR 10, 100, 255
|
||||
|
||||
|
||||
|
||||
#endif // VMIX_DEFINES_H
|
||||
6
docs/_config.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
theme: jekyll-theme-minimal
|
||||
title: vimix
|
||||
description: Video Live Mixer
|
||||
logo: vimix_256x256.png
|
||||
show_downloads: true
|
||||
|
||||
BIN
docs/images/SRT broadcast 1.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
docs/images/SRT broadcast 2.png
Normal file
|
After Width: | Height: | Size: 971 KiB |
BIN
docs/images/SRT vimix receive 1.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
docs/images/SRT vimix receive 2.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
docs/images/SRT vimix receive 3.png
Normal file
|
After Width: | Height: | Size: 381 KiB |
BIN
docs/images/Screenshot-stream-confirm.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/images/Screenshot-stream-open.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
docs/images/Screenshot-stream-out.png
Normal file
|
After Width: | Height: | Size: 429 KiB |
BIN
docs/images/TouchOSC Mk1 vimix current.jpg
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
docs/images/TouchOSC Mk1 vimix mixing.jpg
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 0.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 1.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 2.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 3.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 4.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 5.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 6.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 7.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
docs/images/TouchOSC Mk1 vimix tuto 8.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/images/manual_appearance_0.png
Normal file
|
After Width: | Height: | Size: 436 KiB |
BIN
docs/images/manual_appearance_1.png
Normal file
|
After Width: | Height: | Size: 987 KiB |
BIN
docs/images/manual_appearance_2.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
docs/images/manual_appearance_3.png
Normal file
|
After Width: | Height: | Size: 745 KiB |
BIN
docs/images/manual_appearance_4.png
Normal file
|
After Width: | Height: | Size: 694 KiB |
BIN
docs/images/manual_appearance_5.png
Normal file
|
After Width: | Height: | Size: 496 KiB |
BIN
docs/images/manual_clonefilter_0.png
Normal file
|
After Width: | Height: | Size: 338 KiB |
BIN
docs/images/manual_clonefilter_1.png
Normal file
|
After Width: | Height: | Size: 498 KiB |
BIN
docs/images/manual_clonefilter_2.png
Normal file
|
After Width: | Height: | Size: 913 KiB |