Compare commits
1064 Commits
node-group
...
asset-expe
Author | SHA1 | Date | |
---|---|---|---|
bcc020b1bc | |||
3f36cd3f33 | |||
521222b545 | |||
4a298b10ec | |||
784f7f3264 | |||
70e3f86809 | |||
d8da816a7c | |||
5e469bbd95 | |||
99bb1accbb | |||
b0760a5c8f | |||
581a819432 | |||
6ba8498307 | |||
b18270f43a | |||
3db91def28 | |||
4dd6ffaf37 | |||
4137cc79f2 | |||
b25c224d90 | |||
732cd96737 | |||
71278cc22a | |||
99869dab7c | |||
d012380cae | |||
4c086f6b80 | |||
56677f4f14 | |||
bb4c87a130 | |||
4853f75073 | |||
04ee81a081 | |||
42dda95e89 | |||
21b5ce57f5 | |||
c24ba18d7a | |||
1eac4fde27 | |||
fc10e42de3 | |||
0256d5dde9 | |||
7cbe356c4f | |||
bde19b57d6 | |||
dbf7d30744 | |||
d430237282 | |||
5fd97c6e85 | |||
1880cb6c75 | |||
25e0f5e9f2 | |||
b74ad975fd | |||
0d8e70600b | |||
beaf33dfb2 | |||
46cf8ba269 | |||
f7b21186b5 | |||
fe41942a90 | |||
c6d3f76e69 | |||
69ae86193c | |||
5aaf18c39c | |||
cbf241510d | |||
088d32d159 | |||
d24c85fc12 | |||
595159614f | |||
98654a9c9a | |||
4286b606b3 | |||
09df8bd2e0 | |||
836ecc6142 | |||
0f5642b155 | |||
b1171ea31c | |||
3f4113ce3e | |||
aa5f4d98fc | |||
6f20d64f3a | |||
fd12edebf4 | |||
18f87c8dcb | |||
434a851703 | |||
7282c6592a | |||
77cdf1fb49 | |||
2c9f6714a7 | |||
9400ea0647 | |||
8346805963 | |||
050209d16e | |||
0929283ddc | |||
5afc102357 | |||
6bae015985 | |||
ba1af2e1bf | |||
adbd9cb1de | |||
16641d4c02 | |||
4795d6bdb1 | |||
542302e3f6 | |||
ffe7f4175a | |||
cb530ad07e | |||
084f5e9a4d | |||
4c8e2ebde2 | |||
d27bae4432 | |||
cbe6475383 | |||
93c9ff858a | |||
7cf890e126 | |||
961ebfa8c4 | |||
341237035f | |||
82359a7997 | |||
4a429f1525 | |||
fa21019745 | |||
f4e4575e3c | |||
a6f085f3c9 | |||
39da83e974 | |||
783d63f6af | |||
a6a8ff103d | |||
a97da9842c | |||
861318bbb9 | |||
41c5ec21b3 | |||
b7525de284 | |||
071a27f918 | |||
90af45d5b5 | |||
56ea898ade | |||
d95671442d | |||
26658afad1 | |||
70eb04328c | |||
a47653e5d4 | |||
dd63b849f8 | |||
266d99ee42 | |||
5ad251770b | |||
6c478490ea | |||
e451d9b56a | |||
8bf511ef0b | |||
ef14700089 | |||
20bf7d949f | |||
60cd55692d | |||
b3be710e19 | |||
03d23c42a2 | |||
42ea7490e5 | |||
d4a9111f08 | |||
e812fb4825 | |||
cf08eec187 | |||
32c83ba950 | |||
c2a5f95122 | |||
b1c715a5fa | |||
60474d11c7 | |||
6e1fdd6f2d | |||
6cdc7c9587 | |||
8154ee7bb2 | |||
68eaa00290 | |||
8055eae905 | |||
7cb1438035 | |||
e1c0b2ff25 | |||
54307d778d | |||
1d40cfafea | |||
f36307db4b | |||
9437647f5d | |||
9804f9181f | |||
09f134aa6c | |||
cb926ab6c9 | |||
28382bad00 | |||
5b67ec9c9f | |||
7dea5c2462 | |||
f53c4dd29e | |||
1e3d75604d | |||
897249b254 | |||
718f8fe55f | |||
698b15538b | |||
aec80da8f8 | |||
9a31359e07 | |||
b111e0f645 | |||
8b81b71cf2 | |||
46206fd9a5 | |||
96aa445527 | |||
d63895ee30 | |||
f820643e9f | |||
e9d7c741ca | |||
826ba124b6 | |||
0ab784332a | |||
cab4bd90c1 | |||
c1452617fb | |||
50d2c7f8f4 | |||
f0f46e9ef6 | |||
be5c2a5266 | |||
484f1bc226 | |||
97cb96720c | |||
37c4db1125 | |||
cb770e58ad | |||
09444bca5f | |||
a639446614 | |||
22f5772b44 | |||
8403577397 | |||
ebe52b71a5 | |||
59aeb07895 | |||
b0a541a76c | |||
c93a86909c | |||
204ec489b8 | |||
873e90be65 | |||
30b90cbb01 | |||
f500019eac | |||
3cfea6eadc | |||
304cdfa476 | |||
cea847738a | |||
bb3d3cc9cf | |||
3d4ac80157 | |||
8b4997c6c7 | |||
beff4ca725 | |||
982dd93357 | |||
2fa8db4ec6 | |||
fa4d7deac0 | |||
2a09cb62e2 | |||
0588ca9c08 | |||
bb75900289 | |||
49e2a441cb | |||
ae9ae24c95 | |||
d1dd9b6261 | |||
5b5f55067b | |||
37f58ffec9 | |||
59a1340714 | |||
adfd89d9bd | |||
85959e8b4a | |||
c448d4422e | |||
3dfd063697 | |||
e714e1c5ef | |||
3054a8a91b | |||
dc34313dc9 | |||
afdf2a3fb2 | |||
aabe83d4c0 | |||
9bb32dd445 | |||
87a385b838 | |||
3652a0e7da | |||
b6022f1488 | |||
6a951054d0 | |||
6ec0026f8d | |||
827b1457ca | |||
40562d0e11 | |||
cd43bd241f | |||
a9054360c6 | |||
66375326b4 | |||
3eefdc0ed7 | |||
14d11c1609 | |||
6b61c25815 | |||
576eca8ab3 | |||
ad72025611 | |||
65e357fe56 | |||
46903fbccf | |||
ac2e25986c | |||
71b65b417c | |||
30db6e0cb7 | |||
2ca8421987 | |||
11c6fed3ee | |||
f3de9752fd | |||
1b34246af2 | |||
dded3bb21f | |||
3f63cb8843 | |||
d1b4471012 | |||
5b16d59ffc | |||
f1fc8959db | |||
955cb4a8db | |||
351f74dee9 | |||
da81c78fc7 | |||
911095d372 | |||
d9a93eb3bd | |||
27470754b6 | |||
6b1065b11c | |||
1705fd66d8 | |||
28adc7d248 | |||
f4214d1d1c | |||
48f9931257 | |||
a0803fabfe | |||
6eec8eaa57 | |||
498b712a37 | |||
0fa187e4b5 | |||
a9284fd093 | |||
8af7d783c7 | |||
a7cfb5fc22 | |||
a414edc0af | |||
4c535c07c6 | |||
22f5a17b9c | |||
07b8b90f39 | |||
5a65830830 | |||
f2db96fbaf | |||
2e8297108d | |||
eaa892c14f | |||
f3077f411d | |||
46e6f3b420 | |||
fc7f086f4b | |||
74393f8f15 | |||
9c3e0b558c | |||
e49966dd96 | |||
e921ecabaf | |||
e58cae1b7a | |||
e28986aa8f | |||
19e6c23b75 | |||
9ae928ff9d | |||
b40d4ba517 | |||
8d3129cba2 | |||
009ccfecb6 | |||
f4e7fec73c | |||
a6e9aba17f | |||
b9c5da9ba8 | |||
4eaa6c4a7b | |||
b46b921738 | |||
dab1a1dd5f | |||
24556b3c3d | |||
817fee305f | |||
613bf6755e | |||
f2ce01f844 | |||
3de18048b3 | |||
d02c201814 | |||
c089f28504 | |||
cddbeaeec8 | |||
d0b037d0ef | |||
8bbfd2729a | |||
6dffedc75e | |||
49b67b58aa | |||
67cc51d32d | |||
574d63cf65 | |||
05bd9572a6 | |||
56679ae31c | |||
705a247e2e | |||
e8b46461e6 | |||
9584c88b6b | |||
84d25cb87a | |||
1da2edfb25 | |||
6f90aa2016 | |||
81edad9966 | |||
3319e460e6 | |||
f66e14611d | |||
7ce594b544 | |||
a0df6ce03b | |||
df10b4d7a8 | |||
bfad4bba7a | |||
d35d72893e | |||
b47b035f57 | |||
0c161e23d9 | |||
a6df054b02 | |||
7fa92ad950 | |||
91be63e127 | |||
387b120579 | |||
f1a7118c04 | |||
c9df632175 | |||
11d4cbb04c | |||
e74ce5bd86 | |||
ab5a591f91 | |||
483247d756 | |||
ded1333f3c | |||
4cf00de7d4 | |||
61bad3cfe0 | |||
75c5f6135c | |||
73c8d3abcc | |||
12292d441d | |||
9e6cdd8e3a | |||
7a62ac4127 | |||
d2913c1409 | |||
5f0299898d | |||
9ddc60bc10 | |||
959e2e8cfe | |||
965d9649c4 | |||
033a89957c | |||
e43d70a60f | |||
7f53cbb556 | |||
8b6928b2fb | |||
f0c6c85788 | |||
0c8b1a8c37 | |||
77231eeb2f | |||
9521d71735 | |||
3ad17b9405 | |||
6bf915e925 | |||
c7f48be47c | |||
2d7bc36462 | |||
177295f856 | |||
06b38491f1 | |||
de71f7ab8a | |||
6da735e81c | |||
59ff3b5498 | |||
9a9796564a | |||
a2aafbe656 | |||
d899710952 | |||
a6028f8e6b | |||
3ffc5c9209 | |||
f15741f830 | |||
b89530845a | |||
4dac0afa9c | |||
168604ecbe | |||
9d5cdf92b2 | |||
67d922f61a | |||
4ed3a36e31 | |||
9442a43853 | |||
13faefaf6a | |||
5f2276a553 | |||
e95ba11ce6 | |||
7d1e429d7c | |||
cb08f47121 | |||
84c6bcac0d | |||
74ac2beba2 | |||
741ceed378 | |||
f0ffe42858 | |||
d8a171f8a7 | |||
d4b5b8f1bc | |||
e0c7dcba5b | |||
6188d17623 | |||
a219728914 | |||
92bcc7dd19 | |||
32d9f75660 | |||
249aa6c649 | |||
f2293df9a6 | |||
1daa502f87 | |||
06c6492d7d | |||
6ed0fcc187 | |||
dca705d1c3 | |||
ad8fa268a4 | |||
34c608d010 | |||
b8e224507f | |||
f3e2e92f5c | |||
64f0cd7b33 | |||
7a7b5bc6d3 | |||
2a3e261554 | |||
913938514d | |||
bb6da9cbea | |||
45b83f6fd5 | |||
650efcf2d9 | |||
09dcfbbe46 | |||
a33cc08a99 | |||
5327de0f40 | |||
e0adc0b705 | |||
0548a1dc6f | |||
3b37921e01 | |||
8bb7031dec | |||
d7d236ce5c | |||
a5d1709771 | |||
794a977bad | |||
44e62635c5 | |||
f00f3496a0 | |||
d5f35c6c4e | |||
e2aab5750b | |||
a4c3d645ed | |||
b63872cd5e | |||
e734bef9d6 | |||
105c6a6c26 | |||
45f25c6241 | |||
1a8727fea0 | |||
ad6495d14b | |||
fe3c796c31 | |||
099eb3111e | |||
dd266202b0 | |||
1636b12d4d | |||
9e64ad1ad5 | |||
6fb87bc545 | |||
919a887399 | |||
921a86b51f | |||
5b02b2429a | |||
2282a80697 | |||
931570b480 | |||
063aea9124 | |||
b5ee93c1a3 | |||
e6fa18cebf | |||
0b4439994f | |||
f330da10db | |||
53c28a790b | |||
ff7b6d36e3 | |||
0b8a47d1b0 | |||
9960295484 | |||
113979e658 | |||
c4a3c9d006 | |||
a7e540d7c8 | |||
56dae06c56 | |||
2cdd19de0b | |||
96092913fb | |||
6e88990a4b | |||
19f05f274a | |||
4c486c075e | |||
6b49cc1221 | |||
4058333c49 | |||
d5c69ffeb9 | |||
8da4413ba3 | |||
fc3822988c | |||
2665b3ee83 | |||
5186e5a0c9 | |||
cf7e75ad53 | |||
1b75f74086 | |||
7a5edf3b45 | |||
2c0faad6d5 | |||
a508d49e33 | |||
5bc6608ea5 | |||
06eb69b892 | |||
9b9dbb5865 | |||
f0d843cf56 | |||
47328499cb | |||
62fdf030c6 | |||
db33f64a89 | |||
3f9a6f9fea | |||
d990888686 | |||
37e21ea855 | |||
1d75fe5b95 | |||
5a53d20efc | |||
bcf4cc37ff | |||
e6a84d5a48 | |||
3391a5ed2f | |||
e91d614e4e | |||
ac797f03ef | |||
c18849bb1b | |||
8cbc05c1cd | |||
99008d4841 | |||
d02aa8c4fd | |||
0e62a00bc4 | |||
33b7772563 | |||
f7a3ead1c7 | |||
c7d931b6d2 | |||
2e564ce19c | |||
1d4e36a4c9 | |||
bcbbee4f73 | |||
f5b0c53531 | |||
aaab73d54d | |||
38670bc9a9 | |||
98efbb312c | |||
5ac9844083 | |||
856ef065b2 | |||
f011cdcc11 | |||
32ea612fcc | |||
80ddd9afd9 | |||
5d8b0a8bcc | |||
33a4a4ed8f | |||
7df45b2a49 | |||
1ba2646706 | |||
c7e14ac1f8 | |||
87a3de5852 | |||
f9eef9a678 | |||
185c216743 | |||
4ee210857a | |||
49156ee77b | |||
0df9a4ae3d | |||
18cddb58c4 | |||
3cce86e4d3 | |||
ab9126b7b5 | |||
2622e4b208 | |||
258725cf49 | |||
962751c1a0 | |||
2f43d7a099 | |||
648ce6a080 | |||
b428df5408 | |||
6fda73fe0e | |||
68096bb8e8 | |||
8f496e7ebf | |||
8ae125e946 | |||
5c029b1628 | |||
15f08697e7 | |||
efb2d755c1 | |||
07136e6176 | |||
0abb0ee156 | |||
1fd6979bdb | |||
13d9d33158 | |||
93fb699e20 | |||
6d2519250a | |||
06f937c9b1 | |||
8094de89ce | |||
b4861a9ec1 | |||
283da2a596 | |||
2d861d68a7 | |||
ec99859c44 | |||
a77cd3e953 | |||
3f22fbf32b | |||
65a108cf35 | |||
62ff31971a | |||
75db37e80f | |||
baa1513603 | |||
2420f8a32e | |||
e8af25479d | |||
aa4896317d | |||
031aab8d0c | |||
317474e231 | |||
b9110048f9 | |||
6711e9d15f | |||
173ffb140a | |||
211ef292ba | |||
f5140d4e82 | |||
03829f7c48 | |||
9fc2d1e35b | |||
f5f06db832 | |||
3a21279bc8 | |||
0baa1469d0 | |||
dc659c05d4 | |||
47e73e6b72 | |||
67282959af | |||
979d22b361 | |||
53312d1fac | |||
a2a3e40cf1 | |||
2aab8c7a95 | |||
14786d653a | |||
386efee483 | |||
9ebdab0e17 | |||
6b34b4f066 | |||
d2bdc66143 | |||
231237f1b5 | |||
37e679772e | |||
574a7da03e | |||
1ebdfb4d45 | |||
df50b8cabf | |||
f2d6e85212 | |||
313fabd310 | |||
93563c5522 | |||
c1589b71c5 | |||
aee44d5070 | |||
09787f03b7 | |||
4e2f5a6461 | |||
f37adc4312 | |||
2bfd60e54f | |||
610a04ab5d | |||
222a199f99 | |||
82d166df72 | |||
83dd16a6d6 | |||
4181f35014 | |||
266f0d3e77 | |||
9a2ae72156 | |||
37a6a92f76 | |||
5a16f29700 | |||
80acaa3009 | |||
05017bc9a3 | |||
047525019a | |||
6cb2f6e870 | |||
9f176db5ea | |||
c2049e740e | |||
665ac71aee | |||
dd15ef2528 | |||
effabf0ce7 | |||
a1c8d693a8 | |||
2cac2ec784 | |||
23c81d8990 | |||
633e3d2545 | |||
cd980e85d7 | |||
857d5f3580 | |||
b5a65fd7be | |||
9379b7f968 | |||
fb43c07681 | |||
6c8e34e59b | |||
011061ab5e | |||
7b84fa5927 | |||
6f236221c6 | |||
c3492716ee | |||
ae569a4e76 | |||
924ff970cc | |||
d6b5f82bae | |||
1e1cc1409b | |||
9a7d5130ec | |||
649b09debb | |||
f616871e62 | |||
3d9da00815 | |||
bfb6155466 | |||
edb87ecd75 | |||
bc43854651 | |||
5fbd8997c2 | |||
27ed6ef95c | |||
c3866a0fe1 | |||
04f7493588 | |||
a4965036a7 | |||
22abc19145 | |||
b5635fb70d | |||
7793df2491 | |||
edf50e3a5d | |||
7cc52cc8dd | |||
44adb244bc | |||
e1a3c1d4e7 | |||
aab3ec8624 | |||
89db98c0be | |||
221142275c | |||
c436a00372 | |||
f2f4c4c93d | |||
d4e5cad70e | |||
0f285b566d | |||
b57abacd8c | |||
7f59c846a7 | |||
21e498acdd | |||
5301ea7b96 | |||
2a5d07773e | |||
ab049a335d | |||
74aeb8ef11 | |||
99a3e09088 | |||
b87e275429 | |||
a4c5aa208d | |||
bae3805edb | |||
9ab309901d | |||
bd0e78bb23 | |||
f34c098f0c | |||
23beab242a | |||
99cf8b2188 | |||
180958cb2c | |||
f6dc0573f8 | |||
ac516fddb2 | |||
a5c580c9e4 | |||
b5db0c903c | |||
59a8cbc49b | |||
0a52a358fa | |||
223e098ca1 | |||
7f7f296475 | |||
a9efb6a5ae | |||
b5c72b15ed | |||
85499bb5e8 | |||
952ef0fedf | |||
044398c786 | |||
b0f1a9e27f | |||
3bef09f672 | |||
9706ec852d | |||
ade786b30c | |||
63d52d7bb1 | |||
113c17ea76 | |||
9346891c3c | |||
acd076a9f3 | |||
51a3024f33 | |||
bf583c8c95 | |||
f2ceb38ce8 | |||
47a7246a5c | |||
dd2034623c | |||
b1ce5e6772 | |||
c77f3b57bc | |||
abed546672 | |||
71a061bc1a | |||
6cae0ccded | |||
4767de15b8 | |||
97798c6125 | |||
9d9ee6699a | |||
b943f6fd28 | |||
3745062bf9 | |||
0e5789c43c | |||
ef484c7a59 | |||
d0799901f7 | |||
fc5adb63a0 | |||
85406569e1 | |||
54e753f85e | |||
0bdf85afde | |||
1ca9c549f9 | |||
056f11ec8d | |||
bc8ad4c739 | |||
870c2040bc | |||
2f477065a0 | |||
cc02a0a7e5 | |||
e0c275e239 | |||
92123e578a | |||
56b3d8d273 | |||
40dd7cbe21 | |||
756bb6b404 | |||
839cc7b2a1 | |||
59d5f5c253 | |||
c31c62c7ec | |||
863f19431d | |||
45164ac6e3 | |||
eca9cb2adb | |||
31e89b1fcf | |||
ba20e06227 | |||
b3c8192715 | |||
00e451015b | |||
399b2927df | |||
a9d5eddc52 | |||
eb9784dea2 | |||
b239c249ac | |||
ab9f937bd8 | |||
8124e69a91 | |||
5ffbf49439 | |||
fde14db489 | |||
c4a1d5143e | |||
163ad29b58 | |||
52db10355b | |||
68bab334e0 | |||
18f18ec8b3 | |||
80c0f3da22 | |||
63318a2a4c | |||
476a1b9eff | |||
2842949e13 | |||
b3ad658b45 | |||
449e1d8074 | |||
11ef8d9797 | |||
2feeea8328 | |||
026f967dff | |||
6adc839e40 | |||
e39242c4ce | |||
0e3a9530da | |||
23bba70da5 | |||
bf19bf0110 | |||
eb8b2413de | |||
336c7f9ba5 | |||
96f060d32d | |||
126e1aa60a | |||
bfb977534f | |||
57786fda42 | |||
9763ba8f72 | |||
990598e60c | |||
485a9abf29 | |||
d9c690b559 | |||
a2b4d96b65 | |||
b3de44cc01 | |||
6e8cc0bc05 | |||
b6ef6da231 | |||
fc543da843 | |||
eaf71f7f17 | |||
bdf2e64255 | |||
5cee945744 | |||
c539aaf19d | |||
979d16e52f | |||
718e84201a | |||
5e593dd851 | |||
75ef507e70 | |||
51bb1cef39 | |||
6704abce7f | |||
868a4288ab | |||
4696bce257 | |||
bbfe0652eb | |||
c0748c4292 | |||
e836c116ac | |||
f2e55db040 | |||
e75c5c35cc | |||
744c029d01 | |||
0d4ac96da0 | |||
e70139964d | |||
6ec52ce5eb | |||
d07aeb2fce | |||
7bfe994093 | |||
d8169c2db7 | |||
a592525a7e | |||
c61d6e36ba | |||
49951df23d | |||
0dc6b92fe6 | |||
ce3a8f9f5b | |||
46d777f017 | |||
fd5e70fc99 | |||
f970994cd3 | |||
982fdbf506 | |||
c1617cccd1 | |||
e7c7b00fe0 | |||
8093c5c2a8 | |||
bf3bba802d | |||
2984d39a46 | |||
11df07e53f | |||
ef0367d094 | |||
188419ac3d | |||
7a749ebbcf | |||
e7dbb4b217 | |||
fca4cda7f9 | |||
26d28b755b | |||
9fbec44247 | |||
a9f02fda07 | |||
8834875281 | |||
8bc8015657 | |||
9553016ec1 | |||
01b6fd1f3e | |||
3f860e0e73 | |||
cdfd3c17f5 | |||
bc40f4852d | |||
99373c918f | |||
920bf9f2f3 | |||
18baac2502 | |||
9cf2583126 | |||
0661b80aa0 | |||
0473ff213e | |||
025b502f98 | |||
f3c6cc9f32 | |||
60783fd64e | |||
7059cd538f | |||
4621ac3ac1 | |||
f9adc7fbac | |||
e615009ae4 | |||
f751e34f91 | |||
47ce2c5574 | |||
ec3eec1ac5 | |||
47e3d34d94 | |||
ab463cb324 | |||
ccd1479200 | |||
8da3bb3885 | |||
473e702d5d | |||
da53656be1 | |||
99404d3a70 | |||
4504d50012 | |||
9c6abdff3a | |||
8f0709f9eb | |||
32f4fb952a | |||
5d732ddcae | |||
9f61207b23 | |||
1dcff09045 | |||
7142e653b6 | |||
f6c3f08690 | |||
beee21d045 | |||
c5fde2845e | |||
f2bff41cd5 | |||
65b49051fb | |||
de58d865b6 | |||
6771aeeff5 | |||
02c09be238 | |||
25e0d0d63d | |||
543984ffff | |||
a35de360d0 | |||
ae294763aa | |||
52d3e71302 | |||
21ae02a327 | |||
da7092ff7d | |||
cf89c7aa28 | |||
f7f71bb152 | |||
fb94004e6f | |||
29d3cbc6f9 | |||
156c5bc41e | |||
e08fd1ebe5 | |||
b32de3eaff | |||
a759d0190b | |||
3e6aa7bd08 | |||
a35ced0b97 | |||
14ff7cdf76 | |||
ecb79a5bd5 | |||
d893c9f198 | |||
07042a8d5d | |||
d78819caf9 | |||
ec071eb76a | |||
5e25fdd514 | |||
fb2c646dee | |||
3e603b606c | |||
4c02644a58 | |||
c6ea9e8f48 | |||
05390dc4b5 | |||
09a09c1010 | |||
5144dcaeab | |||
e9484fa25e | |||
92ef1b997b | |||
6f603ea0d2 | |||
67eb234783 | |||
ec4b79fb60 | |||
08bccfed6c | |||
d8567fc45d | |||
51bc0a2b5d | |||
8374fe855e | |||
399ae5d41a | |||
ad1399acc4 | |||
d04a0baae7 | |||
c0d0b3db66 | |||
8b19837b83 | |||
f6b9cad064 | |||
9a4eb983be | |||
93da0a8187 | |||
b3cd561032 | |||
8ebe85f733 | |||
9efd36bac0 | |||
d41e1c00e6 | |||
1c83d9ddbb | |||
ce765ad441 | |||
b3c0b59825 | |||
6f1e2e562d | |||
6199ce89a8 | |||
bdda315260 | |||
50d25aa395 | |||
b1a885ab16 | |||
8ff6e455fa | |||
f1d1073046 | |||
956d8e0ddd | |||
03b7104b72 | |||
2d98ce2e72 | |||
de3fd8a45c | |||
d7b0bc9522 | |||
548029c000 | |||
0715b73e18 | |||
912cdb2acb | |||
5fccc64f6d | |||
c944362fcd | |||
27ce761880 | |||
517b06c296 | |||
3118756854 | |||
d35bbc2a15 | |||
2c7ee72167 | |||
884603573a | |||
67231a22a2 | |||
e53cdbf62f | |||
d46c9b876c | |||
dbd766f827 | |||
de229b4085 | |||
3993965bd7 | |||
97a00b9199 | |||
d237ac45fe | |||
0f44f5506f | |||
d730ff663b | |||
8f4d6f62ea | |||
55c792df8e | |||
7b05fd5830 | |||
67040e08d3 | |||
87518faa20 | |||
e660793896 | |||
224eb0025f | |||
31043d87cd | |||
de0b270014 | |||
0fa91e1723 | |||
aa336809fa | |||
425e8119de | |||
4f241d3d36 | |||
6a7076c9d4 | |||
ba0294cfe0 | |||
0350111424 | |||
8fa24594ce | |||
1d42f07d58 | |||
dc0a4fde63 | |||
00cb0035a7 | |||
4e19102964 | |||
3c52c4ab0a | |||
0357a4928f | |||
4b1f410012 | |||
cfc61a9337 | |||
acaa5b2748 | |||
aa87764d13 | |||
1a5caea321 | |||
242fdf5e60 | |||
b734d9bf17 | |||
4478ddc3d9 | |||
aa24a7d0a5 | |||
d1743e3783 | |||
1dab208eb8 | |||
db9310ac67 | |||
d0187bf624 | |||
baeeacc62d | |||
88ffc9767c | |||
95b103c73b | |||
a79a8fa111 | |||
5cc7df849f | |||
12e3347a5a | |||
c440c22d18 | |||
46d6d74386 | |||
e1a345b3fe | |||
3c738b301f | |||
b3b362a212 | |||
9516d3fafc | |||
ddf519096d | |||
02290ec582 | |||
b36d5570c8 | |||
66f3def3b4 | |||
05926f7253 | |||
002e71f255 | |||
f12f6ddd04 | |||
dfe8884e7a | |||
4f2e8c0315 | |||
812f40c493 | |||
3c634400a0 | |||
8058d7d04f | |||
35554d43b1 | |||
8644862fac | |||
5cf39b228d | |||
b81d5a194a | |||
d211c58856 | |||
7cb8a89aa0 | |||
cb0272ceab | |||
9a7ff0f4fe | |||
769de4ff1e | |||
5d3ee3d695 | |||
3ff51cd5df | |||
e4d9f9b772 | |||
09b3e44b22 | |||
c5fccb7caf | |||
0add26e60b | |||
c725d868af | |||
8f1df9fbba | |||
f06ed97ce7 | |||
f13f85676d | |||
21030e3ae6 | |||
677c716c0f | |||
e28fb66186 | |||
da7f20e385 | |||
6b07e8e31d | |||
ffb0fc35a9 | |||
4e96fe77b1 | |||
337d7b2a6a | |||
f92e64f207 | |||
5eaa8739c5 | |||
c689af14d8 | |||
951dbff60e | |||
53148b5ebc | |||
429cc6072f | |||
b3e2cbac79 | |||
9939e783a9 | |||
276286aa85 | |||
5ceec532b7 | |||
9ea42ae3ba | |||
f8f82821ef | |||
d9b4186e6e | |||
c728f537ae | |||
1089d97f04 | |||
d00d1d5622 | |||
f02bc0cda8 | |||
b65d8de56a | |||
158e6fd7f3 | |||
ff1ff9823d | |||
ca70271876 | |||
b29258922f | |||
99a1f8172b | |||
74ae847cfa |
@@ -642,6 +642,10 @@ class RenderEngine(StructRNA, metaclass=RNAMeta):
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
|
||||||
|
class AssetEngine(StructRNA, metaclass=RNAMeta):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
|
||||||
class KeyingSetInfo(StructRNA, metaclass=RNAMeta):
|
class KeyingSetInfo(StructRNA, metaclass=RNAMeta):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
@@ -51,6 +51,8 @@ _modules = [
|
|||||||
"wm",
|
"wm",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
_modules.append("amber")
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
if bpy.app.build_options.freestyle:
|
if bpy.app.build_options.freestyle:
|
||||||
|
718
release/scripts/startup/bl_operators/amber.py
Normal file
718
release/scripts/startup/bl_operators/amber.py
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# ##### END GPL LICENSE BLOCK #####
|
||||||
|
|
||||||
|
# <pep8 compliant>
|
||||||
|
|
||||||
|
# Note: This will be a simple addon later, but until it gets to master, it's simpler to have it
|
||||||
|
# as a startup module!
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy.types import (
|
||||||
|
AssetEngine,
|
||||||
|
Panel,
|
||||||
|
PropertyGroup,
|
||||||
|
UIList,
|
||||||
|
)
|
||||||
|
from bpy.props import (
|
||||||
|
StringProperty,
|
||||||
|
BoolProperty,
|
||||||
|
IntProperty,
|
||||||
|
FloatProperty,
|
||||||
|
EnumProperty,
|
||||||
|
CollectionProperty,
|
||||||
|
)
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import concurrent.futures as futures
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
AMBER_DB_NAME = "__amber_db.json"
|
||||||
|
AMBER_DBK_VERSION = "version"
|
||||||
|
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Helpers.
|
||||||
|
|
||||||
|
# Notes about UUIDs:
|
||||||
|
# * UUID of an asset/variant/revision is computed once at its creation! Later changes to data do not affect it.
|
||||||
|
# * Collision, for unlikely it is, may happen across different repositories...
|
||||||
|
# Doubt this will be practical issue though.
|
||||||
|
# * We keep eight first bytes of 'clear' identifier, to (try to) keep some readable uuid.
|
||||||
|
|
||||||
|
def _uuid_gen_single(used_uuids, uuid_root, h, str_arg):
|
||||||
|
h.update(str_arg.encode())
|
||||||
|
uuid = uuid_root + h.digest()
|
||||||
|
uuid = uuid[:23].replace(b'\0', b'\1') # No null chars, RNA 'bytes' use them as in regular strings... :/
|
||||||
|
if uuid not in used_uuids: # *Very* likely, but...
|
||||||
|
used_uuids.add(uuid)
|
||||||
|
return uuid
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _uuid_gen(used_uuids, uuid_root, bytes_seed, *str_args):
|
||||||
|
h = hashlib.md5(bytes_seed)
|
||||||
|
for arg in str_args:
|
||||||
|
uuid = _uuid_gen_single(used_uuids, uuid_root, h, arg)
|
||||||
|
if uuid is not None:
|
||||||
|
return uuid
|
||||||
|
# This is a fallback in case we'd get a collision... Should never be needed in real life!
|
||||||
|
for i in range(100000):
|
||||||
|
uuid = _uuid_gen_single(used_uuids, uuid_root, h, i.to_bytes(4, 'little'))
|
||||||
|
if uuid is not None:
|
||||||
|
return uuid
|
||||||
|
return None # If this happens...
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_asset_gen(used_uuids, path_db, name, tags):
|
||||||
|
uuid_root = name.encode()[:8] + b'|'
|
||||||
|
return _uuid_gen_single(used_uuids, uuid_root, path_db.encode(), name, *tags)
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_variant_gen(used_uuids, asset_uuid, name):
|
||||||
|
uuid_root = name.encode()[:8] + b'|'
|
||||||
|
return _uuid_gen_single(used_uuids, uuid_root, asset_uuid, name)
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_revision_gen(used_uuids, variant_uuid, number, size, time):
|
||||||
|
uuid_root = str(number).encode() + b'|'
|
||||||
|
return _uuid_gen_single(used_uuids, uuid_root, variant_uuid, str(number), str(size), str(timestamp))
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_unpack_bytes(uuid_bytes):
|
||||||
|
return struct.unpack("!iiii", uuid_bytes.ljust(16, b'\0'))
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_unpack(uuid_hexstr):
|
||||||
|
return uuid_unpack_bytes(binascii.unhexlify(uuid_hexstr))
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_unpack_asset(uuid_repo_hexstr, uuid_asset_hexstr):
|
||||||
|
return uuid_unpack_bytes(binascii.unhexlify(uuid_repo_hexstr).ljust(8, b'\0') +
|
||||||
|
binascii.unhexlify(uuid_asset_hexstr).ljust(8, b'\0'))
|
||||||
|
|
||||||
|
|
||||||
|
def uuid_pack(uuid_iv4):
|
||||||
|
print(uuid_iv4)
|
||||||
|
return binascii.hexlify(struct.pack("!iiii", *uuid_iv4))
|
||||||
|
|
||||||
|
|
||||||
|
# XXX Hack, once this becomes a real addon we'll just use addons' config system, for now store that in some own config.
|
||||||
|
amber_repos_path = os.path.join(bpy.utils.user_resource('CONFIG', create=True), "amber_repos.json")
|
||||||
|
amber_repos = None
|
||||||
|
if not os.path.exists(amber_repos_path):
|
||||||
|
with open(amber_repos_path, 'w') as ar_f:
|
||||||
|
json.dump({}, ar_f)
|
||||||
|
with open(amber_repos_path, 'r') as ar_f:
|
||||||
|
amber_repos = {uuid_unpack(uuid): path for uuid, path in json.load(ar_f).items()}
|
||||||
|
assert(amber_repos != None)
|
||||||
|
|
||||||
|
|
||||||
|
def save_amber_repos():
|
||||||
|
ar = {uuid_pack(uuid).decode(): path for uuid, path in amber_repos.items()}
|
||||||
|
with open(amber_repos_path, 'w') as ar_f:
|
||||||
|
json.dump(ar, ar_f)
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Amber Jobs.
|
||||||
|
class AmberJob:
|
||||||
|
def __init__(self, executor, job_id):
|
||||||
|
self.executor = executor
|
||||||
|
self.job_id = job_id
|
||||||
|
self.status = {'VALID'}
|
||||||
|
self.progress = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
class AmberJobList(AmberJob):
|
||||||
|
@staticmethod
|
||||||
|
def ls_repo(db_path):
|
||||||
|
repo = None
|
||||||
|
with open(db_path, 'r') as db_f:
|
||||||
|
repo = json.load(db_f)
|
||||||
|
if isinstance(repo, dict):
|
||||||
|
repo_ver = repo.get(AMBER_DBK_VERSION, "")
|
||||||
|
if repo_ver != "1.0.1":
|
||||||
|
# Unsupported...
|
||||||
|
print("WARNING: unsupported Amber repository version '%s'." % repo_ver)
|
||||||
|
repo = None
|
||||||
|
else:
|
||||||
|
repo = None
|
||||||
|
if repo is not None:
|
||||||
|
# Convert hexa string to array of four uint32...
|
||||||
|
# XXX will have to check endianess mess here, for now always use same one ('network' one).
|
||||||
|
repo_uuid = repo["uuid"]
|
||||||
|
repo["uuid"] = uuid_unpack(repo_uuid)
|
||||||
|
new_entries = {}
|
||||||
|
for euuid, e in repo["entries"].items():
|
||||||
|
new_variants = {}
|
||||||
|
for vuuid, v in e["variants"].items():
|
||||||
|
new_revisions = {}
|
||||||
|
for ruuid, r in v["revisions"].items():
|
||||||
|
new_revisions[uuid_unpack(ruuid)] = r
|
||||||
|
new_variants[uuid_unpack(vuuid)] = v
|
||||||
|
v["revisions"] = new_revisions
|
||||||
|
ruuid = v["revision_default"]
|
||||||
|
v["revision_default"] = uuid_unpack(ruuid)
|
||||||
|
new_entries[uuid_unpack_asset(repo_uuid, euuid)] = e
|
||||||
|
e["variants"] = new_variants
|
||||||
|
vuuid = e["variant_default"]
|
||||||
|
e["variant_default"] = uuid_unpack(vuuid)
|
||||||
|
repo["entries"] = new_entries
|
||||||
|
#~ print(repo)
|
||||||
|
return repo
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ls(path):
|
||||||
|
repo = None
|
||||||
|
ret = [".."]
|
||||||
|
tmp = os.listdir(path)
|
||||||
|
if AMBER_DB_NAME in tmp:
|
||||||
|
# That dir is an Amber repo, we only list content define by our amber 'db'.
|
||||||
|
repo = AmberJobList.ls_repo(os.path.join(path, AMBER_DB_NAME))
|
||||||
|
if repo is None:
|
||||||
|
ret += tmp
|
||||||
|
#~ time.sleep(0.1) # 100% Artificial Lag (c)
|
||||||
|
return ret, repo
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stat(root, path):
|
||||||
|
st = os.lstat(root + path)
|
||||||
|
#~ time.sleep(0.1) # 100% Artificial Lag (c)
|
||||||
|
return path, (stat.S_ISDIR(st.st_mode), st.st_size, st.st_mtime)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.nbr = 0
|
||||||
|
self.tot = 0
|
||||||
|
self.ls_task = self.executor.submit(self.ls, self.root)
|
||||||
|
self.status = {'VALID', 'RUNNING'}
|
||||||
|
|
||||||
|
def update(self, repository, dirs):
|
||||||
|
self.status = {'VALID', 'RUNNING'}
|
||||||
|
if self.ls_task is not None:
|
||||||
|
if not self.ls_task.done():
|
||||||
|
return
|
||||||
|
paths, repo = self.ls_task.result()
|
||||||
|
self.ls_task = None
|
||||||
|
self.tot = len(paths)
|
||||||
|
repository.clear()
|
||||||
|
dirs.clear()
|
||||||
|
if repo is not None:
|
||||||
|
repository.update(repo)
|
||||||
|
for p in paths:
|
||||||
|
self.stat_tasks.add(self.executor.submit(self.stat, self.root, p))
|
||||||
|
|
||||||
|
done = set()
|
||||||
|
for tsk in self.stat_tasks:
|
||||||
|
if tsk.done():
|
||||||
|
path, (is_dir, size, timestamp) = tsk.result()
|
||||||
|
self.nbr += 1
|
||||||
|
if is_dir:
|
||||||
|
# We only list dirs from real file system.
|
||||||
|
uuid = uuid_unpack_bytes((path.encode()[:8] + b"|" + self.nbr.to_bytes(4, 'little')))
|
||||||
|
dirs.append((path, size, timestamp, uuid))
|
||||||
|
done.add(tsk)
|
||||||
|
self.stat_tasks -= done
|
||||||
|
|
||||||
|
self.progress = self.nbr / self.tot
|
||||||
|
if not self.stat_tasks and self.ls_task is None:
|
||||||
|
self.status = {'VALID'}
|
||||||
|
|
||||||
|
def __init__(self, executor, job_id, root):
|
||||||
|
super().__init__(executor, job_id)
|
||||||
|
self.root = root
|
||||||
|
|
||||||
|
self.ls_task = None
|
||||||
|
self.stat_tasks = set()
|
||||||
|
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
# Avoid useless work!
|
||||||
|
if self.ls_task is not None:
|
||||||
|
self.ls_task.cancel()
|
||||||
|
for tsk in self.stat_tasks:
|
||||||
|
tsk.cancel()
|
||||||
|
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Main Asset Engine class.
|
||||||
|
class AmberTag(PropertyGroup):
|
||||||
|
name = StringProperty(name="Name", description="Tag name")
|
||||||
|
priority = IntProperty(name="Priority", default=0, description="Tag priority")
|
||||||
|
|
||||||
|
def include_update(self, context):
|
||||||
|
if self.use_include:
|
||||||
|
self.use_exclude = False
|
||||||
|
context.space_data.asset_engine.is_dirty_filtering = True
|
||||||
|
use_include = BoolProperty(name="Include", default=False, description="This tag must exist in filtered items",
|
||||||
|
update=include_update)
|
||||||
|
|
||||||
|
def exclude_update(self, context):
|
||||||
|
if self.use_exclude:
|
||||||
|
self.use_include = False
|
||||||
|
context.space_data.asset_engine.is_dirty_filtering = True
|
||||||
|
use_exclude = BoolProperty(name="Exclude", default=False, description="This tag must not exist in filtered items",
|
||||||
|
update=exclude_update)
|
||||||
|
|
||||||
|
|
||||||
|
class AssetEngineAmber(AssetEngine):
|
||||||
|
bl_label = "Amber"
|
||||||
|
bl_version = (0 << 16) + (0 << 8) + 4 # Usual maj.min.rev version scheme...
|
||||||
|
|
||||||
|
tags = CollectionProperty(name="Tags", type=AmberTag, description="Filtering tags")
|
||||||
|
active_tag_index = IntProperty(name="Active Tag", options={'HIDDEN'})
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.executor = futures.ThreadPoolExecutor(8) # Using threads for now, if issues arise we'll switch to process.
|
||||||
|
self.jobs = {}
|
||||||
|
self.repos = {}
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.job_uuid = 1
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
# XXX This errors, saying self has no executor attribute... Suspect some py/RNA funky game. :/
|
||||||
|
# Even though it does not seem to be an issue, this is not nice and shall be fixed somehow.
|
||||||
|
# XXX This is still erroring... Looks like we should rather have a 'remove' callback or so. :|
|
||||||
|
#~ executor = getattr(self, "executor", None)
|
||||||
|
#~ if executor is not None:
|
||||||
|
#~ executor.shutdown(wait=False)
|
||||||
|
pass
|
||||||
|
|
||||||
|
########## Various helpers ##########
|
||||||
|
def reset(self):
|
||||||
|
print("Amber Reset!")
|
||||||
|
self.root = ""
|
||||||
|
self.repo = {}
|
||||||
|
self.dirs = []
|
||||||
|
|
||||||
|
self.sortedfiltered = []
|
||||||
|
|
||||||
|
def entry_from_uuid(self, entries, euuid, vuuid, ruuid):
|
||||||
|
e = self.repo["entries"][euuid]
|
||||||
|
entry = entries.entries.add()
|
||||||
|
entry.uuid = euuid
|
||||||
|
entry.name = e["name"]
|
||||||
|
entry.description = e["description"]
|
||||||
|
entry.type = {e["file_type"]}
|
||||||
|
entry.blender_type = e["blen_type"]
|
||||||
|
act_rev = None
|
||||||
|
if vuuid == (0, 0, 0, 0):
|
||||||
|
for vuuid, v in e["variants"].items():
|
||||||
|
variant = entry.variants.add()
|
||||||
|
variant.uuid = vuuid
|
||||||
|
variant.name = v["name"]
|
||||||
|
variant.description = v["description"]
|
||||||
|
if vuuid == e["variant_default"]:
|
||||||
|
entry.variants.active = variant
|
||||||
|
for ruuid, r in v["revisions"].items():
|
||||||
|
revision = variant.revisions.add()
|
||||||
|
revision.uuid = ruuid
|
||||||
|
#~ revision.comment = r["comment"]
|
||||||
|
revision.size = r["size"]
|
||||||
|
revision.timestamp = r["timestamp"]
|
||||||
|
if ruuid == v["revision_default"]:
|
||||||
|
variant.revisions.active = revision
|
||||||
|
if vuuid == e["variant_default"]:
|
||||||
|
act_rev = r
|
||||||
|
else:
|
||||||
|
v = e["variants"][vuuid]
|
||||||
|
variant = entry.variants.add()
|
||||||
|
variant.uuid = vuuid
|
||||||
|
variant.name = v["name"]
|
||||||
|
variant.description = v["description"]
|
||||||
|
entry.variants.active = variant
|
||||||
|
if ruuid == (0, 0, 0, 0):
|
||||||
|
for ruuid, r in v["revisions"].items():
|
||||||
|
revision = variant.revisions.add()
|
||||||
|
revision.uuid = ruuid
|
||||||
|
#~ revision.comment = r["comment"]
|
||||||
|
revision.size = r["size"]
|
||||||
|
revision.timestamp = r["timestamp"]
|
||||||
|
if ruuid == v["revision_default"]:
|
||||||
|
variant.revisions.active = revision
|
||||||
|
act_rev = r
|
||||||
|
else:
|
||||||
|
r = v["revisions"][ruuid]
|
||||||
|
revision = variant.revisions.add()
|
||||||
|
revision.uuid = ruuid
|
||||||
|
#~ revision.comment = r["comment"]
|
||||||
|
revision.size = r["size"]
|
||||||
|
revision.timestamp = r["timestamp"]
|
||||||
|
variant.revisions.active = revision
|
||||||
|
act_rev = r
|
||||||
|
if act_rev:
|
||||||
|
entry.relpath = act_rev["path"]
|
||||||
|
# print("added entry for", entry.relpath)
|
||||||
|
|
||||||
|
def pretty_version(self, v=None):
|
||||||
|
if v is None:
|
||||||
|
v = self.bl_version
|
||||||
|
return "%d.%d.%d" % ((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF)
|
||||||
|
|
||||||
|
########## PY-API only ##########
|
||||||
|
# UI header
|
||||||
|
def draw_header(self, layout, context):
|
||||||
|
st = context.space_data
|
||||||
|
params = st.params
|
||||||
|
|
||||||
|
# can be None when save/reload with a file selector open
|
||||||
|
if params:
|
||||||
|
is_lib_browser = params.use_library_browsing
|
||||||
|
|
||||||
|
layout.prop(params, "display_type", expand=True, text="")
|
||||||
|
layout.prop(params, "sort_method", expand=True, text="")
|
||||||
|
|
||||||
|
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
|
||||||
|
layout.prop(params, "use_filter", text="", icon='FILTER')
|
||||||
|
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.active = params.use_filter
|
||||||
|
|
||||||
|
if params.filter_glob:
|
||||||
|
#if st.active_operator and hasattr(st.active_operator, "filter_glob"):
|
||||||
|
# row.prop(params, "filter_glob", text="")
|
||||||
|
row.label(params.filter_glob)
|
||||||
|
else:
|
||||||
|
row.prop(params, "use_filter_blender", text="")
|
||||||
|
row.prop(params, "use_filter_backup", text="")
|
||||||
|
row.prop(params, "use_filter_image", text="")
|
||||||
|
row.prop(params, "use_filter_movie", text="")
|
||||||
|
row.prop(params, "use_filter_script", text="")
|
||||||
|
row.prop(params, "use_filter_font", text="")
|
||||||
|
row.prop(params, "use_filter_sound", text="")
|
||||||
|
row.prop(params, "use_filter_text", text="")
|
||||||
|
|
||||||
|
if is_lib_browser:
|
||||||
|
row.prop(params, "use_filter_blendid", text="")
|
||||||
|
if (params.use_filter_blendid) :
|
||||||
|
row.separator()
|
||||||
|
row.prop(params, "filter_id_category", text="")
|
||||||
|
|
||||||
|
row.separator()
|
||||||
|
row.prop(params, "filter_search", text="", icon='VIEWZOOM')
|
||||||
|
|
||||||
|
########## C (RNA) API ##########
|
||||||
|
def status(self, job_id):
|
||||||
|
if job_id:
|
||||||
|
job = self.jobs.get(job_id, None)
|
||||||
|
return job.status if job is not None else set()
|
||||||
|
return {'VALID'}
|
||||||
|
|
||||||
|
def progress(self, job_id):
|
||||||
|
if job_id:
|
||||||
|
job = self.jobs.get(job_id, None)
|
||||||
|
return job.progress if job is not None else 0.0
|
||||||
|
progress = 0.0
|
||||||
|
nbr_jobs = 0
|
||||||
|
for job in self.jobs.values():
|
||||||
|
if 'RUNNING' in job.status:
|
||||||
|
nbr_jobs += 1
|
||||||
|
progress += job.progress
|
||||||
|
return progress / nbr_jobs if nbr_jobs else 0.0
|
||||||
|
|
||||||
|
def kill(self, job_id):
|
||||||
|
if job_id:
|
||||||
|
self.jobs.pop(job_id, None)
|
||||||
|
return
|
||||||
|
self.jobs.clear()
|
||||||
|
|
||||||
|
def list_dir(self, job_id, entries):
|
||||||
|
job = self.jobs.get(job_id, None)
|
||||||
|
#~ print(entries.root_path, job_id, job)
|
||||||
|
if job is not None and isinstance(job, AmberJobList):
|
||||||
|
if job.root != entries.root_path:
|
||||||
|
self.reset()
|
||||||
|
self.jobs[job_id] = AmberJobList(self.executor, job_id, entries.root_path)
|
||||||
|
self.root = entries.root_path
|
||||||
|
else:
|
||||||
|
job.update(self.repo, self.dirs)
|
||||||
|
elif self.root != entries.root_path:
|
||||||
|
self.reset()
|
||||||
|
job_id = self.job_uuid
|
||||||
|
self.job_uuid += 1
|
||||||
|
self.jobs[job_id] = AmberJobList(self.executor, job_id, entries.root_path)
|
||||||
|
self.root = entries.root_path
|
||||||
|
if self.repo:
|
||||||
|
uuid_repo = self.repo["uuid"]
|
||||||
|
if amber_repos.get(uuid_repo, None) != self.root:
|
||||||
|
amber_repos[uuid_repo] = self.root # XXX Not resistant to uuids collisions (use a set instead)...
|
||||||
|
save_amber_repos()
|
||||||
|
self.repos[uuid_repo] = self.repo
|
||||||
|
entries.nbr_entries = len(self.repo["entries"])
|
||||||
|
valid_tags = set()
|
||||||
|
for name, prio in sorted(self.repo["tags"].items(), key=lambda i: i[1], reverse=True):
|
||||||
|
tag = self.tags.get(name)
|
||||||
|
if tag is None:
|
||||||
|
tag = self.tags.add()
|
||||||
|
tag.name = name
|
||||||
|
tag.priority = prio
|
||||||
|
valid_tags.add(name)
|
||||||
|
for name in (set(self.tags.keys()) - valid_tags):
|
||||||
|
del self.tags[name]
|
||||||
|
else:
|
||||||
|
entries.nbr_entries = len(self.dirs)
|
||||||
|
self.tags.clear()
|
||||||
|
return job_id
|
||||||
|
|
||||||
|
def update_check(self, job_id, uuids):
|
||||||
|
# do nothing for now, no need to use actual job...
|
||||||
|
if uuids.asset_engine_version != self.bl_version:
|
||||||
|
print("Updating asset uuids from Amber v.%s to amber v.%s" %
|
||||||
|
(self.pretty_version(uuids.asset_engine_version), self.pretty_version()))
|
||||||
|
for uuid in uuids.uuids:
|
||||||
|
repo_uuid = uuid.uuid_asset[:2] + (0, 0)
|
||||||
|
if repo_uuid not in amber_repos or not os.path.exists(os.path.join(amber_repos[repo_uuid], AMBER_DB_NAME)):
|
||||||
|
uuid.is_asset_missing = True
|
||||||
|
continue
|
||||||
|
# Here in theory here we'd reload given repo (async process) and check for asset's status...
|
||||||
|
uuid.use_asset_reload = True
|
||||||
|
return self.job_id_invalid
|
||||||
|
|
||||||
|
def load_pre(self, uuids, entries):
|
||||||
|
# Not quite sure this engine will need it in the end, but for sake of testing...
|
||||||
|
if uuids.asset_engine_version != self.bl_version:
|
||||||
|
print("Updating asset uuids from Amber v.%s to amber v.%s" %
|
||||||
|
(self.pretty_version(uuids.asset_engine_version), self.pretty_version()))
|
||||||
|
# print(entries.entries[:])
|
||||||
|
for uuid in uuids.uuids:
|
||||||
|
repo_uuid = tuple(uuid.uuid_asset)[:2] + (0, 0)
|
||||||
|
assert(repo_uuid in amber_repos)
|
||||||
|
repo = self.repos.get(repo_uuid, None)
|
||||||
|
if repo is None:
|
||||||
|
repo = self.repos[repo_uuid] = AmberJobList.ls_repo(os.path.join(amber_repos[repo_uuid], AMBER_DB_NAME))
|
||||||
|
euuid = tuple(uuid.uuid_asset)
|
||||||
|
vuuid = tuple(uuid.uuid_variant)
|
||||||
|
ruuid = tuple(uuid.uuid_revision)
|
||||||
|
e = repo["entries"][euuid]
|
||||||
|
v = e["variants"][vuuid]
|
||||||
|
r = v["revisions"][ruuid]
|
||||||
|
|
||||||
|
entry = entries.entries.add()
|
||||||
|
entry.type = {e["file_type"]}
|
||||||
|
entry.blender_type = e["blen_type"]
|
||||||
|
# archive part not yet implemented!
|
||||||
|
entry.relpath = os.path.join(amber_repos[repo_uuid], r["path"])
|
||||||
|
# print("added entry for", entry.relpath)
|
||||||
|
entry.uuid = euuid
|
||||||
|
var = entry.variants.add()
|
||||||
|
var.uuid = vuuid
|
||||||
|
rev = var.revisions.add()
|
||||||
|
rev.uuid = ruuid
|
||||||
|
var.revisions.active = rev
|
||||||
|
entry.variants.active = var
|
||||||
|
entries.root_path = ""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def check_dir(self, entries):
|
||||||
|
# Stupid code just for test...
|
||||||
|
#~ entries.root_path = entries.root_path + "../"
|
||||||
|
#~ print(entries.root_path)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sort_filter(self, use_sort, use_filter, params, entries):
|
||||||
|
# print(use_sort, use_filter)
|
||||||
|
if use_filter:
|
||||||
|
filter_search = params.filter_search
|
||||||
|
self.sortedfiltered.clear()
|
||||||
|
if self.repo:
|
||||||
|
if params.use_filter:
|
||||||
|
file_type = set()
|
||||||
|
blen_type = set()
|
||||||
|
tags_incl = {t.name for t in self.tags if t.use_include}
|
||||||
|
tags_excl = {t.name for t in self.tags if t.use_exclude}
|
||||||
|
if params.use_filter_image:
|
||||||
|
file_type.add('IMAGE')
|
||||||
|
if params.use_filter_blender:
|
||||||
|
file_type.add('BLENDER')
|
||||||
|
if params.use_filter_backup:
|
||||||
|
file_type.add('BACKUP')
|
||||||
|
if params.use_filter_movie:
|
||||||
|
file_type.add('MOVIE')
|
||||||
|
if params.use_filter_script:
|
||||||
|
file_type.add('SCRIPT')
|
||||||
|
if params.use_filter_font:
|
||||||
|
file_type.add('FONT')
|
||||||
|
if params.use_filter_sound:
|
||||||
|
file_type.add('SOUND')
|
||||||
|
if params.use_filter_text:
|
||||||
|
file_type.add('TEXT')
|
||||||
|
if params.use_filter_blendid and params.use_library_browsing:
|
||||||
|
file_type.add('BLENLIB')
|
||||||
|
blen_type = params.filter_id
|
||||||
|
|
||||||
|
for key, val in self.repo["entries"].items():
|
||||||
|
if filter_search and filter_search not in (val["name"] + val["description"]):
|
||||||
|
continue
|
||||||
|
if params.use_filter:
|
||||||
|
if val["file_type"] not in file_type:
|
||||||
|
continue
|
||||||
|
if params.use_library_browsing and val["blen_type"] not in blen_type:
|
||||||
|
continue
|
||||||
|
if tags_incl or tags_excl:
|
||||||
|
tags = set(val["tags"])
|
||||||
|
if tags_incl and ((tags_incl & tags) != tags_incl):
|
||||||
|
continue
|
||||||
|
if tags_excl and (tags_excl & tags):
|
||||||
|
continue
|
||||||
|
self.sortedfiltered.append((key, val))
|
||||||
|
|
||||||
|
elif self.dirs:
|
||||||
|
for path, size, timestamp, uuid in self.dirs:
|
||||||
|
if filter_search and filter_search not in path:
|
||||||
|
continue
|
||||||
|
if not params.show_hidden and path.startswith(".") and not path.startswith(".."):
|
||||||
|
continue
|
||||||
|
self.sortedfiltered.append((path, size, timestamp, uuid))
|
||||||
|
use_sort = True
|
||||||
|
entries.nbr_entries_filtered = len(self.sortedfiltered) + (1 if self.repo else 0)
|
||||||
|
|
||||||
|
if use_sort:
|
||||||
|
if self.repo:
|
||||||
|
if params.sort_method == 'FILE_SORT_TIME':
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[1]["variants"][e[1]["variant_default"]]["revisions"][e[1]["variants"][e[1]["variant_default"]]["revision_default"]]["timestamp"])
|
||||||
|
elif params.sort_method == 'FILE_SORT_SIZE':
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[1]["variants"][e[1]["variant_default"]]["revisions"][e[1]["variants"][e[1]["variant_default"]]["revision_default"]]["size"])
|
||||||
|
elif params.sort_method == 'FILE_SORT_EXTENSION':
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[1]["blen_type"])
|
||||||
|
else:
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[1]["name"].lower())
|
||||||
|
else:
|
||||||
|
if params.sort_method == 'FILE_SORT_TIME':
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[2])
|
||||||
|
elif params.sort_method == 'FILE_SORT_SIZE':
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[1])
|
||||||
|
else:
|
||||||
|
self.sortedfiltered.sort(key=lambda e: e[0].lower())
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def entries_block_get(self, start_index, end_index, entries):
|
||||||
|
# print(entries.entries[:])
|
||||||
|
if self.repo:
|
||||||
|
if start_index == 0:
|
||||||
|
entry = entries.entries.add()
|
||||||
|
entry.type = {'DIR'}
|
||||||
|
entry.relpath = '..'
|
||||||
|
variant = entry.variants.add()
|
||||||
|
entry.variants.active = variant
|
||||||
|
rev = variant.revisions.add()
|
||||||
|
variant.revisions.active = rev
|
||||||
|
else:
|
||||||
|
start_index -= 1
|
||||||
|
end_index -= 1
|
||||||
|
#~ print("self repo", len(self.sortedfiltered), start_index, end_index)
|
||||||
|
for euuid, e in self.sortedfiltered[start_index:end_index]:
|
||||||
|
self.entry_from_uuid(entries, euuid, (0, 0, 0, 0), (0, 0, 0, 0))
|
||||||
|
else:
|
||||||
|
#~ print("self dirs", len(self.sortedfiltered), start_index, end_index)
|
||||||
|
for path, size, timestamp, uuid in self.sortedfiltered[start_index:end_index]:
|
||||||
|
entry = entries.entries.add()
|
||||||
|
entry.type = {'DIR'}
|
||||||
|
entry.relpath = path
|
||||||
|
# print("added entry for", entry.relpath)
|
||||||
|
entry.uuid = uuid
|
||||||
|
variant = entry.variants.add()
|
||||||
|
entry.variants.active = variant
|
||||||
|
rev = variant.revisions.add()
|
||||||
|
rev.size = size
|
||||||
|
rev.timestamp = timestamp
|
||||||
|
variant.revisions.active = rev
|
||||||
|
return True
|
||||||
|
|
||||||
|
def entries_uuid_get(self, uuids, entries):
|
||||||
|
# print(entries.entries[:])
|
||||||
|
if self.repo:
|
||||||
|
for uuid in uuids.uuids:
|
||||||
|
self.entry_from_uuid(entries, tuple(uuid.uuid_asset), tuple(uuid.uuid_variant), tuple(uuid.uuid_revision))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
##########
|
||||||
|
# UI stuff
|
||||||
|
class AMBER_UL_tags_filter(UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||||
|
# assert(isinstance(item, bpy.types.AmberTag))
|
||||||
|
ae_amber = data
|
||||||
|
tag = item
|
||||||
|
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||||
|
split = layout.split(0.66, False)
|
||||||
|
split.prop(tag, "name", text="", emboss=False, icon_value=icon)
|
||||||
|
row = split.row(align=True)
|
||||||
|
sub = row.row(align=True)
|
||||||
|
sub.active = tag.use_include
|
||||||
|
sub.prop(tag, "use_include", emboss=False, text="", icon='ZOOMIN')
|
||||||
|
sub = row.row(align=True)
|
||||||
|
sub.active = tag.use_exclude
|
||||||
|
sub.prop(tag, "use_exclude", emboss=False, text="", icon='ZOOMOUT')
|
||||||
|
elif self.layout_type == 'GRID':
|
||||||
|
layout.alignment = 'CENTER'
|
||||||
|
layout.label(text="", icon_value=icon)
|
||||||
|
|
||||||
|
|
||||||
|
class AmberPanel():
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
space = context.space_data
|
||||||
|
if space and space.type == 'FILE_BROWSER':
|
||||||
|
ae = space.asset_engine
|
||||||
|
if ae and space.asset_engine_type == "AssetEngineAmber":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class AMBER_PT_options(Panel, AmberPanel):
|
||||||
|
bl_space_type = 'FILE_BROWSER'
|
||||||
|
bl_region_type = 'TOOLS'
|
||||||
|
bl_category = "Asset Engine"
|
||||||
|
bl_label = "Amber Options"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
space = context.space_data
|
||||||
|
ae = space.asset_engine
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
|
||||||
|
|
||||||
|
class AMBER_PT_tags(Panel, AmberPanel):
|
||||||
|
bl_space_type = 'FILE_BROWSER'
|
||||||
|
bl_region_type = 'TOOLS'
|
||||||
|
bl_category = "Filter"
|
||||||
|
bl_label = "Tags"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
ae = context.space_data.asset_engine
|
||||||
|
|
||||||
|
# Note: This is *ultra-primitive*!
|
||||||
|
# A good UI will most likely need new widget option anyway (template). Or maybe just some UIList...
|
||||||
|
#~ self.layout.props_enum(ae, "tags")
|
||||||
|
self.layout.template_list("AMBER_UL_tags_filter", "", ae, "tags", ae, "active_tag_index")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # only for live edit.
|
||||||
|
bpy.utils.register_module(__name__)
|
@@ -28,11 +28,16 @@ class FILEBROWSER_HT_header(Header):
|
|||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
st = context.space_data
|
st = context.space_data
|
||||||
|
params = st.params
|
||||||
|
is_lib_browser = params and params.use_library_browsing
|
||||||
|
|
||||||
layout.template_header()
|
layout.template_header()
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
row = layout.row()
|
if is_lib_browser:
|
||||||
row.separator()
|
row = layout.row()
|
||||||
|
row.prop(st, "asset_engine_type", text="")
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.operator("file.previous", text="", icon='BACK')
|
row.operator("file.previous", text="", icon='BACK')
|
||||||
@@ -41,55 +46,57 @@ class FILEBROWSER_HT_header(Header):
|
|||||||
row.operator("file.refresh", text="", icon='FILE_REFRESH')
|
row.operator("file.refresh", text="", icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.operator_context = 'EXEC_DEFAULT'
|
if st.asset_engine and is_lib_browser:
|
||||||
layout.operator("file.directory_new", icon='NEWFOLDER', text="")
|
draw_header = getattr(st.asset_engine, "draw_header", None)
|
||||||
layout.separator()
|
if draw_header:
|
||||||
|
draw_header(layout, context)
|
||||||
|
else:
|
||||||
|
layout.operator_context = 'EXEC_DEFAULT'
|
||||||
|
layout.operator("file.directory_new", icon='NEWFOLDER', text="")
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
layout.operator_context = 'INVOKE_DEFAULT'
|
layout.operator_context = 'INVOKE_DEFAULT'
|
||||||
params = st.params
|
|
||||||
|
|
||||||
# can be None when save/reload with a file selector open
|
# can be None when save/reload with a file selector open
|
||||||
if params:
|
if params:
|
||||||
is_lib_browser = params.use_library_browsing
|
layout.prop(params, "recursion_level", text="")
|
||||||
|
|
||||||
layout.prop(params, "recursion_level", text="")
|
layout.prop(params, "display_type", expand=True, text="")
|
||||||
|
|
||||||
layout.prop(params, "display_type", expand=True, text="")
|
layout.prop(params, "display_size", text="")
|
||||||
|
|
||||||
layout.prop(params, "display_size", text="")
|
layout.prop(params, "sort_method", expand=True, text="")
|
||||||
|
|
||||||
layout.prop(params, "sort_method", expand=True, text="")
|
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
|
||||||
|
layout.prop(params, "use_filter", text="", icon='FILTER')
|
||||||
|
|
||||||
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
|
row = layout.row(align=True)
|
||||||
layout.prop(params, "use_filter", text="", icon='FILTER')
|
row.active = params.use_filter
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row.prop(params, "use_filter_folder", text="")
|
||||||
row.active = params.use_filter
|
|
||||||
|
|
||||||
row.prop(params, "use_filter_folder", text="")
|
if params.filter_glob:
|
||||||
|
# if st.active_operator and hasattr(st.active_operator, "filter_glob"):
|
||||||
|
# row.prop(params, "filter_glob", text="")
|
||||||
|
row.label(params.filter_glob)
|
||||||
|
else:
|
||||||
|
row.prop(params, "use_filter_blender", text="")
|
||||||
|
row.prop(params, "use_filter_backup", text="")
|
||||||
|
row.prop(params, "use_filter_image", text="")
|
||||||
|
row.prop(params, "use_filter_movie", text="")
|
||||||
|
row.prop(params, "use_filter_script", text="")
|
||||||
|
row.prop(params, "use_filter_font", text="")
|
||||||
|
row.prop(params, "use_filter_sound", text="")
|
||||||
|
row.prop(params, "use_filter_text", text="")
|
||||||
|
|
||||||
if params.filter_glob:
|
if is_lib_browser:
|
||||||
# if st.active_operator and hasattr(st.active_operator, "filter_glob"):
|
row.prop(params, "use_filter_blendid", text="")
|
||||||
# row.prop(params, "filter_glob", text="")
|
if params.use_filter_blendid:
|
||||||
row.label(params.filter_glob)
|
row.separator()
|
||||||
else:
|
row.prop(params, "filter_id_category", text="")
|
||||||
row.prop(params, "use_filter_blender", text="")
|
|
||||||
row.prop(params, "use_filter_backup", text="")
|
|
||||||
row.prop(params, "use_filter_image", text="")
|
|
||||||
row.prop(params, "use_filter_movie", text="")
|
|
||||||
row.prop(params, "use_filter_script", text="")
|
|
||||||
row.prop(params, "use_filter_font", text="")
|
|
||||||
row.prop(params, "use_filter_sound", text="")
|
|
||||||
row.prop(params, "use_filter_text", text="")
|
|
||||||
|
|
||||||
if is_lib_browser:
|
row.separator()
|
||||||
row.prop(params, "use_filter_blendid", text="")
|
row.prop(params, "filter_search", text="", icon='VIEWZOOM')
|
||||||
if params.use_filter_blendid:
|
|
||||||
row.separator()
|
|
||||||
row.prop(params, "filter_id_category", text="")
|
|
||||||
|
|
||||||
row.separator()
|
|
||||||
row.prop(params, "filter_search", text="", icon='VIEWZOOM')
|
|
||||||
|
|
||||||
layout.template_running_jobs()
|
layout.template_running_jobs()
|
||||||
|
|
||||||
|
@@ -68,6 +68,16 @@ class INFO_HT_header(Header):
|
|||||||
row.label(bpy.app.autoexec_fail_message)
|
row.label(bpy.app.autoexec_fail_message)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (bpy.app.assets_fail or bpy.app.assets_need_reload) and not bpy.app.assets_quiet:
|
||||||
|
row.operator("script.assets_warn_clear", text="Ignore")
|
||||||
|
if bpy.app.assets_need_reload is True and bpy.app.assets_quiet is False:
|
||||||
|
#~ row.label(icon='SCREEN_BACK', text="Reload Assets")
|
||||||
|
row.operator("wm.assets_reload", icon='SCREEN_BACK', text="Reload Assets")
|
||||||
|
row.label("Some assets have to be reloaded", icon='INFO')
|
||||||
|
if bpy.app.assets_fail is True and bpy.app.assets_quiet is False:
|
||||||
|
row.label("Some asset engine(s) failed to retrieve updated data about their assets...", icon='ERROR')
|
||||||
|
return
|
||||||
|
|
||||||
row.operator("wm.splash", text="", icon='BLENDER', emboss=False)
|
row.operator("wm.splash", text="", icon='BLENDER', emboss=False)
|
||||||
row.label(text=scene.statistics(), translate=False)
|
row.label(text=scene.statistics(), translate=False)
|
||||||
|
|
||||||
|
246
source/blender/blenkernel/BKE_asset_engine.h
Normal file
246
source/blender/blenkernel/BKE_asset_engine.h
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2015 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): none yet.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file BKE_asset_engine.h
|
||||||
|
* \ingroup bke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BKE_ASSET_ENGINE_H__
|
||||||
|
#define __BKE_ASSET_ENGINE_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "DNA_space_types.h"
|
||||||
|
|
||||||
|
struct AssetEngine;
|
||||||
|
struct AssetEngineType;
|
||||||
|
struct AssetUUIDList;
|
||||||
|
struct FileDirEntryArr;
|
||||||
|
struct FileDirEntry;
|
||||||
|
struct FileDirEntryVariant;
|
||||||
|
struct FileDirEntryRevision;
|
||||||
|
struct ExtensionRNA;
|
||||||
|
struct ID;
|
||||||
|
struct IDProperty;
|
||||||
|
struct ListBase;
|
||||||
|
struct Main;
|
||||||
|
struct ReportList;
|
||||||
|
struct uiLayout;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AE_STATUS_VALID = 1 << 0, /* Asset engine is "OK" (if unset engine won't be used). */
|
||||||
|
AE_STATUS_RUNNING = 1 << 1, /* Asset engine is performing some background tasks... */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AE_FAKE_ENGINE_ID "NONE"
|
||||||
|
|
||||||
|
extern ListBase asset_engines;
|
||||||
|
|
||||||
|
/* AE instance/job is valid, is running, is idle, etc. */
|
||||||
|
typedef int (*ae_status)(struct AssetEngine *engine, const int job_id);
|
||||||
|
|
||||||
|
/* Report progress ([0.0, 1.0] range) of given job. */
|
||||||
|
typedef float (*ae_progress)(struct AssetEngine *engine, const int job_id);
|
||||||
|
|
||||||
|
/* To force end of given job (e.g. because it was cancelled by user...). */
|
||||||
|
typedef void (*ae_kill)(struct AssetEngine *engine, const int job_id);
|
||||||
|
|
||||||
|
/* ***** All callbacks below shall be non-blocking (i.e. return immediately). ***** */
|
||||||
|
|
||||||
|
/* Those callbacks will be called from a 'fake-job' start *and* update functions (i.e. main thread, working one will
|
||||||
|
* just sleep).
|
||||||
|
*
|
||||||
|
* If given id is not AE_JOB_ID_UNSET, engine should update from a running job if available, otherwise it should
|
||||||
|
* start a new one.
|
||||||
|
* It is the responsability of the engine to start/stop background processes to actually perform tasks as/if needed.
|
||||||
|
*
|
||||||
|
* If the engine returns AE_JOB_ID_INVALID as job id, then code assumes whole execution was done in that single first
|
||||||
|
* call (i.e. allows engine that do not need it to not bother with whole async crap - they should then process
|
||||||
|
* the whole request in a very short amount of time (typically below 100ms).
|
||||||
|
*/
|
||||||
|
#define AE_JOB_ID_UNSET 0
|
||||||
|
#define AE_JOB_ID_INVALID -1
|
||||||
|
|
||||||
|
/* FILEBROWSER - List everything available at given root path - only returns numbers of entries! */
|
||||||
|
typedef int (*ae_list_dir)(struct AssetEngine *engine, const int job_id, struct FileDirEntryArr *entries_r);
|
||||||
|
|
||||||
|
/* 'update' hook, called to prepare updating of given entries (typically after a file (re)load).
|
||||||
|
* Engine should check whether given assets are still valid, if they should be updated, etc.
|
||||||
|
* uuids tagged as needing reload will then be reloaded as new ones
|
||||||
|
* (ae_load_pre, then actual lib loading, then ae_load_post).
|
||||||
|
* \warning This callback is expected to handle **real** UUIDS (not 'users' filebrowser ones),
|
||||||
|
* i.e. calling ae_load_pre with those shall **not** alters them in returned direntries
|
||||||
|
* (else 'link' between old IDs and reloaded ones would be broken). */
|
||||||
|
typedef int (*ae_update_check)(struct AssetEngine *engine, const int job_id, struct AssetUUIDList *uuids);
|
||||||
|
|
||||||
|
/* Ensure given assets (uuids) are really available for append/link (some kind of 'anticipated loading'...).
|
||||||
|
* Note: Engine should expect any kind of UUIDs it produced here
|
||||||
|
* (i.e. real ones as well as 'virtual' filebrowsing ones). */
|
||||||
|
typedef int (*ae_ensure_uuids)(struct AssetEngine *engine, const int job_id, struct AssetUUIDList *uuids);
|
||||||
|
|
||||||
|
/* ***** All callbacks below are blocking. They shall be completed upon return. ***** */
|
||||||
|
|
||||||
|
/* FILEBROWSER - Perform sorting and/or filtering on engines' side.
|
||||||
|
* Note that engine is assumed to feature its own sorting/filtering settings!
|
||||||
|
* Number of available filtered entries is to be set in entries_r.
|
||||||
|
*/
|
||||||
|
typedef bool (*ae_sort_filter)(struct AssetEngine *engine, const bool sort, const bool filter,
|
||||||
|
struct FileSelectParams *params, struct FileDirEntryArr *entries_r);
|
||||||
|
|
||||||
|
/* FILEBROWSER - Return specified block of entries in entries_r. */
|
||||||
|
typedef bool (*ae_entries_block_get)(struct AssetEngine *engine, const int start_index, const int end_index,
|
||||||
|
struct FileDirEntryArr *entries_r);
|
||||||
|
|
||||||
|
/* FILEBROWSER - Return specified entries from their uuids, in entries_r. */
|
||||||
|
typedef bool (*ae_entries_uuid_get)(struct AssetEngine *engine, struct AssetUUIDList *uuids,
|
||||||
|
struct FileDirEntryArr *entries_r);
|
||||||
|
|
||||||
|
/* 'pre-loading' hook, called before opening/appending/linking/updating given entries.
|
||||||
|
* Note first given uuid is the one of 'active' entry, and first entry in returned list will be considered as such too.
|
||||||
|
* E.g. allows the engine to ensure entries' paths are actually valid by downloading requested data, etc.
|
||||||
|
* If is_virtual is True, then there is no requirement that returned paths actually exist.
|
||||||
|
* Note that the generated list shall be simpler than the one generated by ae_list_dir, since only the path from
|
||||||
|
* active revision is used, no need to bother with variants, previews, etc.
|
||||||
|
* This allows to present 'fake' entries to user, and then import actual data.
|
||||||
|
*/
|
||||||
|
typedef bool (*ae_load_pre)(struct AssetEngine *engine, struct AssetUUIDList *uuids,
|
||||||
|
struct FileDirEntryArr *entries_r);
|
||||||
|
|
||||||
|
/* 'post-loading' hook, called after opening/appending/linking/updating given entries.
|
||||||
|
* E.g. allows an advanced engine to make fancy scripted operations over loaded items. */
|
||||||
|
/* TODO */
|
||||||
|
typedef bool (*ae_load_post)(struct AssetEngine *engine, struct ID *items, const int *num_items);
|
||||||
|
|
||||||
|
/* Check if given dirpath is valid for current asset engine, it can also modify it.
|
||||||
|
* r_dir is assumed to be least FILE_MAX. */
|
||||||
|
typedef void (*ae_check_dir)(struct AssetEngine *engine, char *r_dir);
|
||||||
|
|
||||||
|
typedef struct AssetEngineType {
|
||||||
|
struct AssetEngineType *next, *prev;
|
||||||
|
|
||||||
|
/* type info */
|
||||||
|
char idname[64]; /* best keep the same size as BKE_ST_MAXNAME */
|
||||||
|
int version;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
/* API */
|
||||||
|
ae_status status;
|
||||||
|
ae_progress progress;
|
||||||
|
|
||||||
|
ae_kill kill;
|
||||||
|
|
||||||
|
ae_list_dir list_dir;
|
||||||
|
ae_sort_filter sort_filter;
|
||||||
|
ae_entries_block_get entries_block_get;
|
||||||
|
ae_entries_uuid_get entries_uuid_get;
|
||||||
|
|
||||||
|
ae_ensure_uuids ensure_uuids;
|
||||||
|
|
||||||
|
ae_load_pre load_pre;
|
||||||
|
ae_load_post load_post;
|
||||||
|
ae_update_check update_check;
|
||||||
|
ae_check_dir check_dir;
|
||||||
|
|
||||||
|
/* RNA integration */
|
||||||
|
struct ExtensionRNA ext;
|
||||||
|
} AssetEngineType;
|
||||||
|
|
||||||
|
typedef struct AssetEngine {
|
||||||
|
AssetEngineType *type;
|
||||||
|
void *py_instance;
|
||||||
|
|
||||||
|
/* Custom sub-classes properties. */
|
||||||
|
IDProperty *properties;
|
||||||
|
|
||||||
|
int flag;
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
struct ReportList *reports;
|
||||||
|
} AssetEngine;
|
||||||
|
|
||||||
|
/* AssetEngine->flag */
|
||||||
|
enum {
|
||||||
|
AE_DIRTY_FILTER = 1 << 0,
|
||||||
|
AE_DIRTY_SORTING = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Engine Types */
|
||||||
|
void BKE_asset_engines_init(void);
|
||||||
|
void BKE_asset_engines_exit(void);
|
||||||
|
|
||||||
|
AssetEngineType *BKE_asset_engines_find(const char *idname);
|
||||||
|
AssetEngineType *BKE_asset_engines_get_default(char *r_idname, const size_t len);
|
||||||
|
|
||||||
|
/* Engine Instances */
|
||||||
|
AssetEngine *BKE_asset_engine_create(AssetEngineType *type, struct ReportList *reports);
|
||||||
|
AssetEngine *BKE_asset_engine_copy(AssetEngine *engine);
|
||||||
|
void BKE_asset_engine_free(AssetEngine *engine);
|
||||||
|
|
||||||
|
struct AssetUUIDList *BKE_asset_engine_entries_load_pre(AssetEngine *engine, struct FileDirEntryArr *r_entries);
|
||||||
|
struct FileDirEntryArr *BKE_asset_engine_uuids_load_pre(AssetEngine *engine, struct AssetUUIDList *r_uuids);
|
||||||
|
|
||||||
|
/* File listing utils... */
|
||||||
|
|
||||||
|
typedef enum FileCheckType {
|
||||||
|
CHECK_NONE = 0,
|
||||||
|
CHECK_DIRS = 1 << 0,
|
||||||
|
CHECK_FILES = 1 << 1,
|
||||||
|
CHECK_ALL = CHECK_DIRS | CHECK_FILES,
|
||||||
|
} FileCheckType;
|
||||||
|
|
||||||
|
void BKE_filedir_revision_free(struct FileDirEntryRevision *rev);
|
||||||
|
|
||||||
|
void BKE_filedir_variant_free(struct FileDirEntryVariant *var);
|
||||||
|
|
||||||
|
void BKE_filedir_entry_free(struct FileDirEntry *entry);
|
||||||
|
void BKE_filedir_entry_clear(struct FileDirEntry *entry);
|
||||||
|
struct FileDirEntry *BKE_filedir_entry_copy(struct FileDirEntry *entry);
|
||||||
|
|
||||||
|
void BKE_filedir_entryarr_clear(struct FileDirEntryArr *array);
|
||||||
|
|
||||||
|
#define ASSETUUID_SUB_COMPARE(_uuida, _uuidb, _member) \
|
||||||
|
(memcmp((_uuida)->_member, (_uuidb)->_member, sizeof((_uuida)->_member)) == 0)
|
||||||
|
|
||||||
|
#define ASSETUUID_COMPARE(_uuida, _uuidb) \
|
||||||
|
(ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_asset) && \
|
||||||
|
ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_variant) && \
|
||||||
|
ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_revision))
|
||||||
|
|
||||||
|
/* Various helpers */
|
||||||
|
unsigned int BKE_asset_uuid_hash(const void *key);
|
||||||
|
bool BKE_asset_uuid_cmp(const void *a, const void *b);
|
||||||
|
void BKE_asset_uuid_print(const struct AssetUUID *uuid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BKE_ASSET_ENGINE_H__ */
|
@@ -104,6 +104,10 @@ typedef struct Global {
|
|||||||
|
|
||||||
/* #define G_FACESELECT (1 << 8) use (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) */
|
/* #define G_FACESELECT (1 << 8) use (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) */
|
||||||
|
|
||||||
|
#define G_ASSETS_NEED_RELOAD (1 << 10)
|
||||||
|
#define G_ASSETS_FAIL (1 << 11)
|
||||||
|
#define G_ASSETS_QUIET (1 << 12)
|
||||||
|
|
||||||
#define G_SCRIPT_AUTOEXEC (1 << 13)
|
#define G_SCRIPT_AUTOEXEC (1 << 13)
|
||||||
#define G_SCRIPT_OVERRIDE_PREF (1 << 14) /* when this flag is set ignore the userprefs */
|
#define G_SCRIPT_OVERRIDE_PREF (1 << 14) /* when this flag is set ignore the userprefs */
|
||||||
#define G_SCRIPT_AUTOEXEC_FAIL (1 << 15)
|
#define G_SCRIPT_AUTOEXEC_FAIL (1 << 15)
|
||||||
|
@@ -38,6 +38,8 @@ extern "C" {
|
|||||||
|
|
||||||
#include "BLI_compiler_attrs.h"
|
#include "BLI_compiler_attrs.h"
|
||||||
|
|
||||||
|
struct AssetEngineType;
|
||||||
|
struct AssetUUID;
|
||||||
struct BlendThumbnail;
|
struct BlendThumbnail;
|
||||||
struct ListBase;
|
struct ListBase;
|
||||||
struct ID;
|
struct ID;
|
||||||
@@ -127,6 +129,20 @@ void BKE_library_free(struct Library *lib);
|
|||||||
void BKE_library_make_local(
|
void BKE_library_make_local(
|
||||||
struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
|
struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_init(struct Library *lib, const struct AssetEngineType *aet, const char *repo_root);
|
||||||
|
void BKE_library_asset_repository_clear(struct Library *lib);
|
||||||
|
void BKE_library_asset_repository_free(struct Library *lib);
|
||||||
|
struct AssetRef *BKE_library_asset_repository_asset_add(struct Library *lib, const void *idv);
|
||||||
|
void BKE_library_asset_repository_asset_remove(struct Library *lib, const void *idv);
|
||||||
|
struct AssetRef *BKE_library_asset_repository_asset_find(struct Library *lib, const void *idv);
|
||||||
|
void BKE_library_asset_repository_subdata_add(struct AssetRef *aref, const void *idv);
|
||||||
|
void BKE_library_asset_repository_subdata_remove(struct AssetRef *aref, const void *idv);
|
||||||
|
|
||||||
|
void BKE_libraries_asset_subdata_remove(struct Main *bmain, const void *idv);
|
||||||
|
void BKE_libraries_asset_repositories_clear(struct Main *bmain);
|
||||||
|
void BKE_libraries_asset_repositories_rebuild(struct Main *bmain);
|
||||||
|
struct AssetRef *BKE_libraries_asset_repository_uuid_find(struct Main *bmain, const struct AssetUUID *uuid);
|
||||||
|
struct Library *BKE_library_asset_virtual_ensure(struct Main *bmain, const struct AssetEngineType *aet);
|
||||||
|
|
||||||
/* use when "" is given to new_id() */
|
/* use when "" is given to new_id() */
|
||||||
#define ID_FALLBACK_NAME N_("Untitled")
|
#define ID_FALLBACK_NAME N_("Untitled")
|
||||||
|
@@ -70,6 +70,7 @@ set(SRC
|
|||||||
intern/appdir.c
|
intern/appdir.c
|
||||||
intern/armature.c
|
intern/armature.c
|
||||||
intern/armature_update.c
|
intern/armature_update.c
|
||||||
|
intern/asset_engine.c
|
||||||
intern/autoexec.c
|
intern/autoexec.c
|
||||||
intern/blender.c
|
intern/blender.c
|
||||||
intern/blender_copybuffer.c
|
intern/blender_copybuffer.c
|
||||||
@@ -118,6 +119,7 @@ set(SRC
|
|||||||
intern/lamp.c
|
intern/lamp.c
|
||||||
intern/lattice.c
|
intern/lattice.c
|
||||||
intern/library.c
|
intern/library.c
|
||||||
|
intern/library_asset.c
|
||||||
intern/library_idmap.c
|
intern/library_idmap.c
|
||||||
intern/library_query.c
|
intern/library_query.c
|
||||||
intern/library_remap.c
|
intern/library_remap.c
|
||||||
@@ -194,6 +196,7 @@ set(SRC
|
|||||||
BKE_animsys.h
|
BKE_animsys.h
|
||||||
BKE_appdir.h
|
BKE_appdir.h
|
||||||
BKE_armature.h
|
BKE_armature.h
|
||||||
|
BKE_asset_engine.h
|
||||||
BKE_autoexec.h
|
BKE_autoexec.h
|
||||||
BKE_blender.h
|
BKE_blender.h
|
||||||
BKE_blender_copybuffer.h
|
BKE_blender_copybuffer.h
|
||||||
|
@@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
|
|||||||
|
|
||||||
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
|
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
|
||||||
{
|
{
|
||||||
BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL);
|
BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
|
||||||
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
|
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
|
||||||
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
|
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
|
||||||
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
|
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
|
||||||
|
428
source/blender/blenkernel/intern/asset_engine.c
Normal file
428
source/blender/blenkernel/intern/asset_engine.c
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2015 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): none yet.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/blenkernel/intern/asset_engine.c
|
||||||
|
* \ingroup bke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
|
#include "BLI_fileops_types.h"
|
||||||
|
#include "BLI_hash_mm2a.h"
|
||||||
|
#include "BLI_listbase.h"
|
||||||
|
#include "BLI_string.h"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
|
#include "PIL_time.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
|
#include "BKE_global.h"
|
||||||
|
#include "BKE_idprop.h"
|
||||||
|
#include "BKE_library.h"
|
||||||
|
#include "BKE_main.h"
|
||||||
|
#include "BKE_report.h"
|
||||||
|
|
||||||
|
#include "IMB_imbuf.h"
|
||||||
|
|
||||||
|
#include "DNA_space_types.h"
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON
|
||||||
|
#include "BPY_extern.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Asset engine types (none intern!). */
|
||||||
|
|
||||||
|
ListBase asset_engines = {NULL, NULL};
|
||||||
|
|
||||||
|
void BKE_asset_engines_init(void)
|
||||||
|
{
|
||||||
|
/* We just add a dummy engine, which 'is' our intern filelisting code from space_file! */
|
||||||
|
AssetEngineType *aet = MEM_callocN(sizeof(*aet), __func__);
|
||||||
|
|
||||||
|
BLI_strncpy(aet->idname, AE_FAKE_ENGINE_ID, sizeof(aet->idname));
|
||||||
|
BLI_strncpy(aet->name, "None", sizeof(aet->name));
|
||||||
|
|
||||||
|
BLI_addhead(&asset_engines, aet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_asset_engines_exit(void)
|
||||||
|
{
|
||||||
|
AssetEngineType *type, *next;
|
||||||
|
|
||||||
|
for (type = asset_engines.first; type; type = next) {
|
||||||
|
next = type->next;
|
||||||
|
|
||||||
|
BLI_remlink(&asset_engines, type);
|
||||||
|
|
||||||
|
if (type->ext.free) {
|
||||||
|
type->ext.free(type->ext.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetEngineType *BKE_asset_engines_find(const char *idname)
|
||||||
|
{
|
||||||
|
AssetEngineType *type;
|
||||||
|
|
||||||
|
type = BLI_findstring(&asset_engines, idname, offsetof(AssetEngineType, idname));
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetEngineType *BKE_asset_engines_get_default(char *r_idname, const size_t len)
|
||||||
|
{
|
||||||
|
AssetEngineType *type = asset_engines.first;
|
||||||
|
|
||||||
|
BLI_assert(type);
|
||||||
|
|
||||||
|
if (r_idname) {
|
||||||
|
BLI_strncpy(r_idname, type->idname, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Asset engine instances. */
|
||||||
|
|
||||||
|
/* Create, Free */
|
||||||
|
|
||||||
|
AssetEngine *BKE_asset_engine_create(AssetEngineType *type, ReportList *reports)
|
||||||
|
{
|
||||||
|
AssetEngine *engine;
|
||||||
|
|
||||||
|
BLI_assert(type);
|
||||||
|
|
||||||
|
engine = MEM_callocN(sizeof(AssetEngine), __func__);
|
||||||
|
engine->type = type;
|
||||||
|
engine->refcount = 1;
|
||||||
|
|
||||||
|
/* initialize error reports */
|
||||||
|
if (reports) {
|
||||||
|
engine->reports = reports; /* must be initialized already */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
engine->reports = MEM_mallocN(sizeof(ReportList), __func__);
|
||||||
|
BKE_reports_init(engine->reports, RPT_STORE | RPT_FREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shalow copy only (i.e. memory is 100% shared, just increases refcount). */
|
||||||
|
AssetEngine *BKE_asset_engine_copy(AssetEngine *engine)
|
||||||
|
{
|
||||||
|
engine->refcount++;
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_asset_engine_free(AssetEngine *engine)
|
||||||
|
{
|
||||||
|
if (engine->refcount-- == 1) {
|
||||||
|
#ifdef WITH_PYTHON
|
||||||
|
if (engine->py_instance) {
|
||||||
|
BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (engine->properties) {
|
||||||
|
IDP_FreeProperty(engine->properties);
|
||||||
|
MEM_freeN(engine->properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (engine->reports && (engine->reports->flag & RPT_FREE)) {
|
||||||
|
BKE_reports_clear(engine->reports);
|
||||||
|
MEM_freeN(engine->reports);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* API helpers. */
|
||||||
|
|
||||||
|
static void asset_engine_load_pre(AssetEngine *engine, AssetUUIDList *r_uuids, FileDirEntryArr *r_entries)
|
||||||
|
{
|
||||||
|
FileDirEntry *en;
|
||||||
|
AssetUUID *uuid;
|
||||||
|
const int nbr_entries = r_entries->nbr_entries ? r_entries->nbr_entries : r_uuids->nbr_uuids;
|
||||||
|
|
||||||
|
if (r_entries->nbr_entries) {
|
||||||
|
BLI_assert(r_uuids->uuids == NULL);
|
||||||
|
r_uuids->uuids = MEM_mallocN(sizeof(*r_uuids->uuids) * nbr_entries, __func__);
|
||||||
|
r_uuids->nbr_uuids = nbr_entries;
|
||||||
|
r_uuids->asset_engine_version = engine->type->version;
|
||||||
|
|
||||||
|
for (en = r_entries->entries.first, uuid = r_uuids->uuids; en; en = en->next, uuid++) {
|
||||||
|
FileDirEntryVariant *var = BLI_findlink(&en->variants, en->act_variant);
|
||||||
|
|
||||||
|
memcpy(uuid->uuid_asset, en->uuid, sizeof(uuid->uuid_asset));
|
||||||
|
|
||||||
|
BLI_assert(var);
|
||||||
|
memcpy(uuid->uuid_variant, var->uuid, sizeof(uuid->uuid_variant));
|
||||||
|
|
||||||
|
memcpy(uuid->uuid_revision, en->entry->uuid, sizeof(uuid->uuid_revision));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_filedir_entryarr_clear(r_entries);
|
||||||
|
|
||||||
|
if (!engine->type->load_pre(engine, r_uuids, r_entries)) {
|
||||||
|
/* If load_pre returns false (i.e. fails), clear all paths! */
|
||||||
|
/* TODO: report!!! */
|
||||||
|
BKE_filedir_entryarr_clear(r_entries);
|
||||||
|
|
||||||
|
MEM_freeN(r_uuids->uuids);
|
||||||
|
r_uuids->uuids = NULL;
|
||||||
|
r_uuids->nbr_uuids = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load_pre may change things, we have to rebuild our uuids list from returned entries. */
|
||||||
|
r_entries->nbr_entries = r_uuids->nbr_uuids = BLI_listbase_count(&r_entries->entries);
|
||||||
|
r_uuids->uuids = MEM_reallocN(r_uuids->uuids, sizeof(*r_uuids->uuids) * r_uuids->nbr_uuids);
|
||||||
|
for (en = r_entries->entries.first, uuid = r_uuids->uuids; en; en = en->next, uuid++) {
|
||||||
|
FileDirEntryVariant *var;
|
||||||
|
FileDirEntryRevision *rev;
|
||||||
|
|
||||||
|
memcpy(uuid->uuid_asset, en->uuid, sizeof(uuid->uuid_asset));
|
||||||
|
|
||||||
|
var = BLI_findlink(&en->variants, en->act_variant);
|
||||||
|
BLI_assert(var);
|
||||||
|
memcpy(uuid->uuid_variant, var->uuid, sizeof(uuid->uuid_variant));
|
||||||
|
|
||||||
|
rev = BLI_findlink(&var->revisions, var->act_revision);
|
||||||
|
BLI_assert(rev);
|
||||||
|
memcpy(uuid->uuid_revision, rev->uuid, sizeof(uuid->uuid_revision));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Call load_pre for given entries, and return new uuids/entries. */
|
||||||
|
AssetUUIDList *BKE_asset_engine_entries_load_pre(AssetEngine *engine, FileDirEntryArr *r_entries)
|
||||||
|
{
|
||||||
|
AssetUUIDList *uuids = MEM_callocN(sizeof(*uuids), __func__);
|
||||||
|
|
||||||
|
asset_engine_load_pre(engine, uuids, r_entries);
|
||||||
|
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Call load_pre for given uuids, and return new uuids/entries. */
|
||||||
|
FileDirEntryArr *BKE_asset_engine_uuids_load_pre(AssetEngine *engine, AssetUUIDList *r_uuids)
|
||||||
|
{
|
||||||
|
FileDirEntryArr *entries = MEM_callocN(sizeof(*entries), __func__);
|
||||||
|
|
||||||
|
asset_engine_load_pre(engine, r_uuids, entries);
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FileDirxxx handling. */
|
||||||
|
|
||||||
|
void BKE_filedir_revision_free(FileDirEntryRevision *rev)
|
||||||
|
{
|
||||||
|
if (rev->comment) {
|
||||||
|
MEM_freeN(rev->comment);
|
||||||
|
}
|
||||||
|
MEM_freeN(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_filedir_variant_free(FileDirEntryVariant *var)
|
||||||
|
{
|
||||||
|
if (var->name) {
|
||||||
|
MEM_freeN(var->name);
|
||||||
|
}
|
||||||
|
if (var->description) {
|
||||||
|
MEM_freeN(var->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BLI_listbase_is_empty(&var->revisions)) {
|
||||||
|
FileDirEntryRevision *rev, *rev_next;
|
||||||
|
|
||||||
|
for (rev = var->revisions.first; rev; rev = rev_next) {
|
||||||
|
rev_next = rev->next;
|
||||||
|
BKE_filedir_revision_free(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_listbase_clear(&var->revisions);
|
||||||
|
}
|
||||||
|
MEM_freeN(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_filedir_entry_clear(FileDirEntry *entry)
|
||||||
|
{
|
||||||
|
if (entry->name) {
|
||||||
|
MEM_freeN(entry->name);
|
||||||
|
}
|
||||||
|
if (entry->description) {
|
||||||
|
MEM_freeN(entry->description);
|
||||||
|
}
|
||||||
|
if (entry->relpath) {
|
||||||
|
MEM_freeN(entry->relpath);
|
||||||
|
}
|
||||||
|
if (entry->image) {
|
||||||
|
IMB_freeImBuf(entry->image);
|
||||||
|
}
|
||||||
|
/* For now, consider FileDirEntryRevision::poin as not owned here, so no need to do anything about it */
|
||||||
|
|
||||||
|
if (!BLI_listbase_is_empty(&entry->variants)) {
|
||||||
|
FileDirEntryVariant *var, *var_next;
|
||||||
|
|
||||||
|
for (var = entry->variants.first; var; var = var_next) {
|
||||||
|
var_next = var->next;
|
||||||
|
BKE_filedir_variant_free(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_listbase_clear(&entry->variants);
|
||||||
|
}
|
||||||
|
else if (entry->entry){
|
||||||
|
MEM_freeN(entry->entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(entry, 0, sizeof(*entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_filedir_entry_free(FileDirEntry *entry)
|
||||||
|
{
|
||||||
|
BKE_filedir_entry_clear(entry);
|
||||||
|
MEM_freeN(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform and return a full (deep) duplicate of given entry. */
|
||||||
|
FileDirEntry *BKE_filedir_entry_copy(FileDirEntry *entry)
|
||||||
|
{
|
||||||
|
FileDirEntry *entry_new = MEM_dupallocN(entry);
|
||||||
|
|
||||||
|
if (entry->name) {
|
||||||
|
entry_new->name = MEM_dupallocN(entry->name);
|
||||||
|
}
|
||||||
|
if (entry->description) {
|
||||||
|
entry_new->description = MEM_dupallocN(entry->description);
|
||||||
|
}
|
||||||
|
if (entry->relpath) {
|
||||||
|
entry_new->relpath = MEM_dupallocN(entry->relpath);
|
||||||
|
}
|
||||||
|
if (entry->image) {
|
||||||
|
entry_new->image = IMB_dupImBuf(entry->image);
|
||||||
|
}
|
||||||
|
/* For now, consider FileDirEntryRevision::poin as not owned here, so no need to do anything about it */
|
||||||
|
|
||||||
|
entry_new->entry = NULL;
|
||||||
|
if (!BLI_listbase_is_empty(&entry->variants)) {
|
||||||
|
FileDirEntryVariant *var;
|
||||||
|
int act_var;
|
||||||
|
|
||||||
|
BLI_listbase_clear(&entry_new->variants);
|
||||||
|
for (act_var = 0, var = entry->variants.first; var; act_var++, var = var->next) {
|
||||||
|
FileDirEntryVariant *var_new = MEM_dupallocN(var);
|
||||||
|
FileDirEntryRevision *rev;
|
||||||
|
const bool is_act_var = (act_var == entry->act_variant);
|
||||||
|
int act_rev;
|
||||||
|
|
||||||
|
if (var->name) {
|
||||||
|
var_new->name = MEM_dupallocN(var->name);
|
||||||
|
}
|
||||||
|
if (var->description) {
|
||||||
|
var_new->description = MEM_dupallocN(var->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_listbase_clear(&var_new->revisions);
|
||||||
|
for (act_rev = 0, rev = var->revisions.first; rev; act_rev++, rev = rev->next) {
|
||||||
|
FileDirEntryRevision *rev_new = MEM_dupallocN(rev);
|
||||||
|
const bool is_act_rev = (act_rev == var->act_revision);
|
||||||
|
|
||||||
|
if (rev->comment) {
|
||||||
|
rev_new->comment = MEM_dupallocN(rev->comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_addtail(&var_new->revisions, rev_new);
|
||||||
|
|
||||||
|
if (is_act_var && is_act_rev) {
|
||||||
|
entry_new->entry = rev_new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_addtail(&entry_new->variants, var_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (entry->entry){
|
||||||
|
entry_new->entry = MEM_dupallocN(entry->entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert(entry_new->entry != NULL);
|
||||||
|
|
||||||
|
/* TODO: tags! */
|
||||||
|
|
||||||
|
return entry_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_filedir_entryarr_clear(FileDirEntryArr *array)
|
||||||
|
{
|
||||||
|
FileDirEntry *entry, *entry_next;
|
||||||
|
|
||||||
|
for (entry = array->entries.first; entry; entry = entry_next) {
|
||||||
|
entry_next = entry->next;
|
||||||
|
BKE_filedir_entry_free(entry);
|
||||||
|
}
|
||||||
|
BLI_listbase_clear(&array->entries);
|
||||||
|
array->nbr_entries = 0;
|
||||||
|
array->nbr_entries_filtered = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Various helpers */
|
||||||
|
unsigned int BKE_asset_uuid_hash(const void *key)
|
||||||
|
{
|
||||||
|
return BLI_hash_mm2((const unsigned char *)key, sizeof(AssetUUID), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BKE_asset_uuid_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const AssetUUID *uuid1 = a;
|
||||||
|
const AssetUUID *uuid2 = b;
|
||||||
|
return !ASSETUUID_COMPARE(uuid1, uuid2); /* Expects false when compared equal... */
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_asset_uuid_print(const AssetUUID *uuid)
|
||||||
|
{
|
||||||
|
/* TODO print nicer (as 128bit hexadecimal...). */
|
||||||
|
printf("[%d,%d,%d,%d][%d,%d,%d,%d][%d,%d,%d,%d]\n",
|
||||||
|
uuid->uuid_asset[0], uuid->uuid_asset[1], uuid->uuid_asset[2], uuid->uuid_asset[3],
|
||||||
|
uuid->uuid_variant[0], uuid->uuid_variant[1], uuid->uuid_variant[2], uuid->uuid_variant[3],
|
||||||
|
uuid->uuid_revision[0], uuid->uuid_revision[1], uuid->uuid_revision[2], uuid->uuid_revision[3]);
|
||||||
|
}
|
@@ -42,9 +42,12 @@
|
|||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_callbacks.h"
|
#include "BLI_callbacks.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
#include "IMB_imbuf.h"
|
#include "IMB_imbuf.h"
|
||||||
#include "IMB_moviecache.h"
|
#include "IMB_moviecache.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_blender.h" /* own include */
|
#include "BKE_blender.h" /* own include */
|
||||||
#include "BKE_blender_version.h" /* own include */
|
#include "BKE_blender_version.h" /* own include */
|
||||||
#include "BKE_blendfile.h"
|
#include "BKE_blendfile.h"
|
||||||
@@ -66,7 +69,6 @@
|
|||||||
|
|
||||||
#include "BLF_api.h"
|
#include "BLF_api.h"
|
||||||
|
|
||||||
|
|
||||||
Global G;
|
Global G;
|
||||||
UserDef U;
|
UserDef U;
|
||||||
|
|
||||||
|
@@ -424,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
|
|||||||
{
|
{
|
||||||
const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
|
const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
|
||||||
|
|
||||||
if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) {
|
if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -225,7 +225,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
|
|||||||
* - mixed: make copy
|
* - mixed: make copy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!ID_IS_LINKED_DATABLOCK(brush)) {
|
if (!ID_IS_LINKED(brush)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
|
|||||||
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
|
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
|
||||||
static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
|
static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
|
||||||
{
|
{
|
||||||
if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin))
|
if (*idpoin && ID_IS_LINKED(*idpoin))
|
||||||
id_lib_extern(*idpoin);
|
id_lib_extern(*idpoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,6 +75,8 @@
|
|||||||
#include "BLI_threads.h"
|
#include "BLI_threads.h"
|
||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
#include "BKE_action.h"
|
#include "BKE_action.h"
|
||||||
#include "BKE_animsys.h"
|
#include "BKE_animsys.h"
|
||||||
#include "BKE_armature.h"
|
#include "BKE_armature.h"
|
||||||
@@ -116,8 +118,6 @@
|
|||||||
|
|
||||||
#include "DEG_depsgraph.h"
|
#include "DEG_depsgraph.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
|
|
||||||
#include "IMB_imbuf.h"
|
#include "IMB_imbuf.h"
|
||||||
#include "IMB_imbuf_types.h"
|
#include "IMB_imbuf_types.h"
|
||||||
|
|
||||||
@@ -134,6 +134,10 @@
|
|||||||
* also note that the id _must_ have a library - campbell */
|
* also note that the id _must_ have a library - campbell */
|
||||||
void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
|
void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
|
||||||
{
|
{
|
||||||
|
if (lib->flag & LIBRARY_FLAG_VIRTUAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char *bpath_user_data[2] = {bmain->name, lib->filepath};
|
const char *bpath_user_data[2] = {bmain->name, lib->filepath};
|
||||||
|
|
||||||
BKE_bpath_traverse_id(bmain, id,
|
BKE_bpath_traverse_id(bmain, id,
|
||||||
@@ -144,7 +148,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
|
|||||||
|
|
||||||
void id_lib_extern(ID *id)
|
void id_lib_extern(ID *id)
|
||||||
{
|
{
|
||||||
if (id && ID_IS_LINKED_DATABLOCK(id)) {
|
if (id && ID_IS_LINKED(id)) {
|
||||||
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
|
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
|
||||||
if (id->tag & LIB_TAG_INDIRECT) {
|
if (id->tag & LIB_TAG_INDIRECT) {
|
||||||
id->tag -= LIB_TAG_INDIRECT;
|
id->tag -= LIB_TAG_INDIRECT;
|
||||||
@@ -276,7 +280,7 @@ void BKE_id_expand_local(ID *id)
|
|||||||
*/
|
*/
|
||||||
void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
|
void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
|
||||||
{
|
{
|
||||||
if (ID_IS_LINKED_DATABLOCK(old_id)) {
|
if (ID_IS_LINKED(old_id)) {
|
||||||
BKE_id_expand_local(new_id);
|
BKE_id_expand_local(new_id);
|
||||||
BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
|
BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
|
||||||
}
|
}
|
||||||
@@ -295,7 +299,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
|
|||||||
* In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
|
* In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!ID_IS_LINKED_DATABLOCK(id)) {
|
if (!ID_IS_LINKED(id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,7 +715,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
|
|||||||
|
|
||||||
/* flag for full recalc */
|
/* flag for full recalc */
|
||||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||||
if (ID_IS_LINKED_DATABLOCK(ob)) {
|
if (ID_IS_LINKED(ob)) {
|
||||||
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
|
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1137,7 +1141,7 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i
|
|||||||
|
|
||||||
void BKE_libblock_relink(ID *id)
|
void BKE_libblock_relink(ID *id)
|
||||||
{
|
{
|
||||||
if (ID_IS_LINKED_DATABLOCK(id))
|
if (ID_IS_LINKED(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
|
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
|
||||||
@@ -1147,6 +1151,8 @@ void BKE_library_free(Library *lib)
|
|||||||
{
|
{
|
||||||
if (lib->packedfile)
|
if (lib->packedfile)
|
||||||
freePackedFile(lib->packedfile);
|
freePackedFile(lib->packedfile);
|
||||||
|
|
||||||
|
BKE_library_asset_repository_free(lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
Main *BKE_main_new(void)
|
Main *BKE_main_new(void)
|
||||||
@@ -1351,7 +1357,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
|
|||||||
|
|
||||||
for (idtest = lb->first; idtest; idtest = idtest->next) {
|
for (idtest = lb->first; idtest; idtest = idtest->next) {
|
||||||
/* if idtest is not a lib */
|
/* if idtest is not a lib */
|
||||||
if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
|
if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { /* Virtual lib IDs are considered as local ones here. */
|
||||||
/* do not test alphabetic! */
|
/* do not test alphabetic! */
|
||||||
/* optimized */
|
/* optimized */
|
||||||
if (idtest->name[2] == name[0]) {
|
if (idtest->name[2] == name[0]) {
|
||||||
@@ -1492,7 +1498,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
|
|||||||
bool result;
|
bool result;
|
||||||
char name[MAX_ID_NAME - 2];
|
char name[MAX_ID_NAME - 2];
|
||||||
|
|
||||||
/* if library, don't rename */
|
/* if real library, don't rename */
|
||||||
if (ID_IS_LINKED_DATABLOCK(id))
|
if (ID_IS_LINKED_DATABLOCK(id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -1688,6 +1694,7 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use after setting the ID's name
|
* Use after setting the ID's name
|
||||||
* When name exists: call 'new_id'
|
* When name exists: call 'new_id'
|
||||||
@@ -1733,6 +1740,11 @@ void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id)
|
|||||||
|
|
||||||
void BKE_library_filepath_set(Library *lib, const char *filepath)
|
void BKE_library_filepath_set(Library *lib, const char *filepath)
|
||||||
{
|
{
|
||||||
|
if (lib->flag & LIBRARY_FLAG_VIRTUAL) {
|
||||||
|
/* Setting path for virtual libraries makes no sense. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* in some cases this is used to update the absolute path from the
|
/* in some cases this is used to update the absolute path from the
|
||||||
* relative */
|
* relative */
|
||||||
if (lib->name != filepath) {
|
if (lib->name != filepath) {
|
||||||
|
269
source/blender/blenkernel/intern/library_asset.c
Normal file
269
source/blender/blenkernel/intern/library_asset.c
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2015,2016 by Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): Bastien Montagne.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/blenkernel/intern/library_asset.c
|
||||||
|
* \ingroup bke
|
||||||
|
*
|
||||||
|
* Contains asset-related management of ID's and libraries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_blenlib.h"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
|
#include "BKE_library.h"
|
||||||
|
#include "BKE_library_query.h"
|
||||||
|
#include "BKE_main.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Asset managing - TODO: we most likely want to turn this into a hashing at some point, could become a bit slow
|
||||||
|
* when having huge assets (or many of them)... */
|
||||||
|
void BKE_library_asset_repository_init(Library *lib, const AssetEngineType *aet, const char *repo_root)
|
||||||
|
{
|
||||||
|
BKE_library_asset_repository_free(lib);
|
||||||
|
lib->asset_repository = MEM_mallocN(sizeof(*lib->asset_repository), __func__);
|
||||||
|
|
||||||
|
BLI_strncpy(lib->asset_repository->asset_engine, aet->idname, sizeof(lib->asset_repository->asset_engine));
|
||||||
|
lib->asset_repository->asset_engine_version = aet->version;
|
||||||
|
BLI_strncpy(lib->asset_repository->root, repo_root, sizeof(lib->asset_repository->root));
|
||||||
|
|
||||||
|
BLI_listbase_clear(&lib->asset_repository->assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_clear(Library *lib)
|
||||||
|
{
|
||||||
|
if (lib->asset_repository) {
|
||||||
|
for (AssetRef *aref; (aref = BLI_pophead(&lib->asset_repository->assets)); ) {
|
||||||
|
BLI_freelistN(&aref->id_list);
|
||||||
|
MEM_freeN(aref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_free(Library *lib)
|
||||||
|
{
|
||||||
|
if (lib->asset_repository) {
|
||||||
|
BKE_library_asset_repository_clear(lib);
|
||||||
|
MEM_freeN(lib->asset_repository);
|
||||||
|
lib->asset_repository = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetRef *BKE_library_asset_repository_asset_add(Library *lib, const void *idv)
|
||||||
|
{
|
||||||
|
const ID *id = idv;
|
||||||
|
BLI_assert(id->uuid != NULL);
|
||||||
|
|
||||||
|
AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
|
||||||
|
if (!aref) {
|
||||||
|
aref = MEM_callocN(sizeof(*aref), __func__);
|
||||||
|
aref->uuid = *id->uuid;
|
||||||
|
BKE_library_asset_repository_subdata_add(aref, idv);
|
||||||
|
BLI_addtail(&lib->asset_repository->assets, aref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return aref;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetRef *BKE_library_asset_repository_asset_find(Library *lib, const void *idv)
|
||||||
|
{
|
||||||
|
const ID *id = idv;
|
||||||
|
BLI_assert(id->uuid != NULL);
|
||||||
|
|
||||||
|
for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
|
||||||
|
if (ASSETUUID_COMPARE(&aref->uuid, id->uuid)) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
LinkData *link = aref->id_list.first;
|
||||||
|
BLI_assert(link && (link->data == idv));
|
||||||
|
#endif
|
||||||
|
return aref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_asset_remove(Library *lib, const void *idv)
|
||||||
|
{
|
||||||
|
AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
|
||||||
|
BLI_remlink(&lib->asset_repository->assets, aref);
|
||||||
|
BLI_freelistN(&aref->id_list);
|
||||||
|
MEM_freeN(aref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_subdata_add(AssetRef *aref, const void *idv)
|
||||||
|
{
|
||||||
|
if (BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)) == NULL) {
|
||||||
|
BLI_addtail(&aref->id_list, BLI_genericNodeN((void *)idv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_library_asset_repository_subdata_remove(AssetRef *aref, const void *idv)
|
||||||
|
{
|
||||||
|
LinkData *link = BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data));
|
||||||
|
if (link) {
|
||||||
|
BLI_freelinkN(&aref->id_list, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_libraries_asset_subdata_remove(Main *bmain, const void *idv)
|
||||||
|
{
|
||||||
|
const ID *id = idv;
|
||||||
|
|
||||||
|
if (id->lib == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListBase *lb = &bmain->library;
|
||||||
|
for (Library *lib = lb->first; lib; lib = lib->id.next) {
|
||||||
|
if (lib->asset_repository) {
|
||||||
|
for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
|
||||||
|
LinkData *subdata = aref->id_list.first;
|
||||||
|
/* Skip first one, it's main asset, not subdata! */
|
||||||
|
for (subdata = subdata->next; subdata; subdata = subdata->next) {
|
||||||
|
if (subdata->data == idv) {
|
||||||
|
BLI_freelinkN(&aref->id_list, subdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_libraries_asset_repositories_clear(Main *bmain)
|
||||||
|
{
|
||||||
|
ListBase *lb = which_libbase(bmain, ID_LI);
|
||||||
|
for (Library *lib = lb->first; lib; lib = lib->id.next) {
|
||||||
|
BKE_library_asset_repository_clear(lib);
|
||||||
|
}
|
||||||
|
BKE_main_id_tag_all(bmain, LIB_TAG_ASSET, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int library_asset_dependencies_rebuild_cb(void *userdata, ID *id_self, ID **idp, int UNUSED(cd_flag))
|
||||||
|
{
|
||||||
|
if (!idp || !*idp) {
|
||||||
|
return IDWALK_RET_NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetRef *aref = userdata;
|
||||||
|
ID *id = *idp;
|
||||||
|
|
||||||
|
if (id->uuid) {
|
||||||
|
return IDWALK_RET_STOP_RECURSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s (from %s)\n", id->name, id_self->name);
|
||||||
|
|
||||||
|
BKE_library_asset_repository_subdata_add(aref, (const void *)id);
|
||||||
|
id->tag |= LIB_TAG_ASSET;
|
||||||
|
return IDWALK_RET_NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void library_asset_dependencies_rebuild(ID *asset)
|
||||||
|
{
|
||||||
|
Library *lib = asset->lib;
|
||||||
|
BLI_assert(lib && lib->asset_repository);
|
||||||
|
|
||||||
|
if (!(lib && lib->asset_repository)) {
|
||||||
|
printf("asset: %s\n", asset->name);
|
||||||
|
printf("lib: %p\n", lib);
|
||||||
|
printf("lib: %s\n", lib->id.name);
|
||||||
|
printf("lib: %s\n", lib->name);
|
||||||
|
printf("lib: %p\n\n\n", lib->asset_repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
asset->tag |= LIB_TAG_ASSET;
|
||||||
|
|
||||||
|
AssetRef *aref = BKE_library_asset_repository_asset_add(lib, asset);
|
||||||
|
|
||||||
|
BKE_library_foreach_ID_link(asset, library_asset_dependencies_rebuild_cb, aref, IDWALK_RECURSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_libraries_asset_repositories_rebuild(Main *bmain)
|
||||||
|
{
|
||||||
|
ListBase *lbarray[MAX_LIBARRAY];
|
||||||
|
ID *id;
|
||||||
|
int a;
|
||||||
|
|
||||||
|
BKE_libraries_asset_repositories_clear(bmain);
|
||||||
|
|
||||||
|
a = set_listbasepointers(bmain, lbarray);
|
||||||
|
while (a--) {
|
||||||
|
for (id = lbarray[a]->first; id; id = id->next) {
|
||||||
|
if (id->uuid) {
|
||||||
|
library_asset_dependencies_rebuild(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetRef *BKE_libraries_asset_repository_uuid_find(Main *bmain, const AssetUUID *uuid)
|
||||||
|
{
|
||||||
|
ListBase *lb = which_libbase(bmain, ID_LI);
|
||||||
|
for (Library *lib = lb->first; lib; lib = lib->id.next) {
|
||||||
|
for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
|
||||||
|
if (ASSETUUID_COMPARE(&aref->uuid, uuid)) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
LinkData *link = aref->id_list.first;
|
||||||
|
BLI_assert(link && ((ID *)link->data)->uuid && ASSETUUID_COMPARE(((ID *)link->data)->uuid, uuid));
|
||||||
|
#endif
|
||||||
|
return aref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find or add the 'virtual' library datablock matching this asset engine, used for non-blend-data assets. */
|
||||||
|
Library *BKE_library_asset_virtual_ensure(Main *bmain, const AssetEngineType *aet)
|
||||||
|
{
|
||||||
|
Library *lib;
|
||||||
|
ListBase *lb = which_libbase(bmain, ID_LI);
|
||||||
|
|
||||||
|
for (lib = lb->first; lib; lib = lib->id.next) {
|
||||||
|
if (!(lib->flag & LIBRARY_FLAG_VIRTUAL) || !lib->asset_repository) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STREQ(lib->asset_repository->asset_engine, aet->idname) &&
|
||||||
|
lib->asset_repository->asset_engine_version == aet->version)
|
||||||
|
{
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lib = BKE_libblock_alloc(bmain, ID_LI, "VirtualLib");
|
||||||
|
BKE_library_asset_repository_init(lib, aet, "");
|
||||||
|
lib->flag |= LIBRARY_FLAG_VIRTUAL;
|
||||||
|
return lib;
|
||||||
|
}
|
@@ -298,7 +298,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
data.self_id = id;
|
data.self_id = id;
|
||||||
data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
|
data.cd_flag = ID_IS_LINKED(id) ? IDWALK_INDIRECT_USAGE : 0;
|
||||||
|
|
||||||
AnimData *adt = BKE_animdata_from_id(id);
|
AnimData *adt = BKE_animdata_from_id(id);
|
||||||
if (adt) {
|
if (adt) {
|
||||||
@@ -447,7 +447,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
|
|||||||
* Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
|
* Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
|
||||||
* if proxy object is linked... Twisted. */
|
* if proxy object is linked... Twisted. */
|
||||||
if (object->proxy_from) {
|
if (object->proxy_from) {
|
||||||
data.cd_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
|
data.cd_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
|
||||||
}
|
}
|
||||||
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
|
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
|
||||||
data.cd_flag = data_cd_flag;
|
data.cd_flag = data_cd_flag;
|
||||||
|
@@ -686,6 +686,10 @@ void BKE_libblock_free_data(Main *bmain, ID *id)
|
|||||||
MEM_freeN(id->properties);
|
MEM_freeN(id->properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id->uuid) {
|
||||||
|
MEM_freeN(id->uuid);
|
||||||
|
}
|
||||||
|
|
||||||
/* this ID may be a driver target! */
|
/* this ID may be a driver target! */
|
||||||
BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
|
BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
|
||||||
}
|
}
|
||||||
|
@@ -707,7 +707,7 @@ void test_object_modifiers(Object *ob)
|
|||||||
*/
|
*/
|
||||||
const char *modifier_path_relbase(Object *ob)
|
const char *modifier_path_relbase(Object *ob)
|
||||||
{
|
{
|
||||||
if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) {
|
if (G.relbase_valid || ID_IS_LINKED(ob)) {
|
||||||
return ID_BLEND_PATH(G.main, &ob->id);
|
return ID_BLEND_PATH(G.main, &ob->id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -2652,7 +2652,7 @@ void BKE_node_clipboard_add_node(bNode *node)
|
|||||||
node_info->id = node->id;
|
node_info->id = node->id;
|
||||||
if (node->id) {
|
if (node->id) {
|
||||||
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
|
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
|
||||||
if (ID_IS_LINKED_DATABLOCK(node->id)) {
|
if (ID_IS_LINKED_DATABLOCK(node->id)) { /* Don't want virtual libraries here... */
|
||||||
BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
|
BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -1193,7 +1193,7 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
|
|||||||
* In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
|
* In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!ID_IS_LINKED_DATABLOCK(ob)) {
|
if (!ID_IS_LINKED(ob)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1220,15 +1220,15 @@ void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
|
|||||||
/* Returns true if the Object is from an external blend file (libdata) */
|
/* Returns true if the Object is from an external blend file (libdata) */
|
||||||
bool BKE_object_is_libdata(Object *ob)
|
bool BKE_object_is_libdata(Object *ob)
|
||||||
{
|
{
|
||||||
return (ob && ID_IS_LINKED_DATABLOCK(ob));
|
return (ob && ID_IS_LINKED(ob));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if the Object data is from an external blend file (libdata) */
|
/* Returns true if the Object data is from an external blend file (libdata) */
|
||||||
bool BKE_object_obdata_is_libdata(Object *ob)
|
bool BKE_object_obdata_is_libdata(Object *ob)
|
||||||
{
|
{
|
||||||
/* Linked objects with local obdata are forbidden! */
|
/* Linked objects with local obdata are forbidden! */
|
||||||
BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true));
|
BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true));
|
||||||
return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data));
|
return (ob && ob->data && ID_IS_LINKED(ob->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************** PROXY **************** */
|
/* *************** PROXY **************** */
|
||||||
@@ -1275,7 +1275,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
|
|||||||
/* only on local objects because this causes indirect links
|
/* only on local objects because this causes indirect links
|
||||||
* 'a -> b -> c', blend to point directly to a.blend
|
* 'a -> b -> c', blend to point directly to a.blend
|
||||||
* when a.blend has a proxy thats linked into c.blend */
|
* when a.blend has a proxy thats linked into c.blend */
|
||||||
if (!ID_IS_LINKED_DATABLOCK(ob))
|
if (!ID_IS_LINKED(ob))
|
||||||
id_lib_extern((ID *)dtar->id);
|
id_lib_extern((ID *)dtar->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1293,7 +1293,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
|
|||||||
void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
|
void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
|
||||||
{
|
{
|
||||||
/* paranoia checks */
|
/* paranoia checks */
|
||||||
if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) {
|
if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
|
||||||
printf("cannot make proxy\n");
|
printf("cannot make proxy\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2670,7 +2670,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
|
|||||||
printf("recalcob %s\n", ob->id.name + 2);
|
printf("recalcob %s\n", ob->id.name + 2);
|
||||||
|
|
||||||
/* handle proxy copy for target */
|
/* handle proxy copy for target */
|
||||||
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
|
if (ID_IS_LINKED(ob) && ob->proxy_from) {
|
||||||
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
|
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
|
||||||
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
|
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
|
||||||
Object *obg = ob->proxy_from->proxy_group;
|
Object *obg = ob->proxy_from->proxy_group;
|
||||||
|
@@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OB_ARMATURE:
|
case OB_ARMATURE:
|
||||||
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
|
if (ID_IS_LINKED(ob) && ob->proxy_from) {
|
||||||
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
|
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
|
||||||
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
|
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
|
||||||
ob->id.name + 2, ob->proxy_from->id.name + 2);
|
ob->id.name + 2, ob->proxy_from->id.name + 2);
|
||||||
@@ -315,7 +315,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
|
|||||||
// XXX: it's almost redundant now...
|
// XXX: it's almost redundant now...
|
||||||
|
|
||||||
/* Handle proxy copy for target, */
|
/* Handle proxy copy for target, */
|
||||||
if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
|
if (ID_IS_LINKED(ob) && ob->proxy_from) {
|
||||||
if (ob->proxy_from->proxy_group) {
|
if (ob->proxy_from->proxy_group) {
|
||||||
/* Transform proxy into group space. */
|
/* Transform proxy into group space. */
|
||||||
Object *obg = ob->proxy_from->proxy_group;
|
Object *obg = ob->proxy_from->proxy_group;
|
||||||
|
@@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
|
|||||||
int tot = 0;
|
int tot = 0;
|
||||||
|
|
||||||
for (ima = bmain->image.first; ima; ima = ima->id.next) {
|
for (ima = bmain->image.first; ima; ima = ima->id.next) {
|
||||||
if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) {
|
if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
|
||||||
if (ima->source == IMA_SRC_FILE) {
|
if (ima->source == IMA_SRC_FILE) {
|
||||||
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
|
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
|
||||||
tot ++;
|
tot ++;
|
||||||
@@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
|
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
|
||||||
if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) {
|
if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) {
|
||||||
vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
|
vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
|
||||||
tot ++;
|
tot ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
|
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
|
||||||
if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) {
|
if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
|
||||||
sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
|
sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
|
||||||
tot++;
|
tot++;
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct AssetEngineType;
|
||||||
|
struct AssetUUID;
|
||||||
struct BlendThumbnail;
|
struct BlendThumbnail;
|
||||||
struct bScreen;
|
struct bScreen;
|
||||||
struct LinkNode;
|
struct LinkNode;
|
||||||
@@ -102,6 +104,11 @@ struct ID *BLO_library_link_named_part_ex(
|
|||||||
const short idcode, const char *name, const short flag,
|
const short idcode, const char *name, const short flag,
|
||||||
struct Scene *scene, struct View3D *v3d,
|
struct Scene *scene, struct View3D *v3d,
|
||||||
const bool use_placeholders, const bool force_indirect);
|
const bool use_placeholders, const bool force_indirect);
|
||||||
|
struct ID *BLO_library_link_named_part_asset(
|
||||||
|
struct Main *mainl, BlendHandle **bh, const struct AssetEngineType *aet, const char *root,
|
||||||
|
const short idcode, const char *name, const struct AssetUUID *uuid, const short flag,
|
||||||
|
struct Scene *scene, struct View3D *v3d,
|
||||||
|
const bool use_placeholders, const bool force_indirect);
|
||||||
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
|
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
|
||||||
|
|
||||||
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
|
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
|
||||||
|
@@ -109,10 +109,13 @@
|
|||||||
#include "BLI_threads.h"
|
#include "BLI_threads.h"
|
||||||
#include "BLI_mempool.h"
|
#include "BLI_mempool.h"
|
||||||
|
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
#include "BKE_action.h"
|
#include "BKE_action.h"
|
||||||
#include "BKE_armature.h"
|
#include "BKE_armature.h"
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_brush.h"
|
#include "BKE_brush.h"
|
||||||
#include "BKE_cloth.h"
|
#include "BKE_cloth.h"
|
||||||
#include "BKE_constraint.h"
|
#include "BKE_constraint.h"
|
||||||
@@ -2160,6 +2163,9 @@ static void direct_link_id(FileData *fd, ID *id)
|
|||||||
/* this case means the data was written incorrectly, it should not happen */
|
/* this case means the data was written incorrectly, it should not happen */
|
||||||
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
|
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
|
||||||
}
|
}
|
||||||
|
if (id->uuid) {
|
||||||
|
id->uuid = newdataadr(fd, id->uuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************ READ CurveMapping *************** */
|
/* ************ READ CurveMapping *************** */
|
||||||
@@ -7174,6 +7180,8 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
|
|||||||
{
|
{
|
||||||
Main *newmain;
|
Main *newmain;
|
||||||
|
|
||||||
|
printf("adding lib %s (%s)\n", lib->id.name, lib->name);
|
||||||
|
|
||||||
/* check if the library was already read */
|
/* check if the library was already read */
|
||||||
for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) {
|
for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) {
|
||||||
if (newmain->curlib) {
|
if (newmain->curlib) {
|
||||||
@@ -7201,7 +7209,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
|
|||||||
// printf("direct_link_library: filepath %s\n", lib->filepath);
|
// printf("direct_link_library: filepath %s\n", lib->filepath);
|
||||||
|
|
||||||
lib->packedfile = direct_link_packedfile(fd, lib->packedfile);
|
lib->packedfile = direct_link_packedfile(fd, lib->packedfile);
|
||||||
|
lib->asset_repository = newdataadr(fd, lib->asset_repository);
|
||||||
|
if (lib->asset_repository) {
|
||||||
|
/* Do not clear lib->asset_repository itself! */
|
||||||
|
BLI_listbase_clear(&lib->asset_repository->assets);
|
||||||
|
}
|
||||||
|
|
||||||
/* new main */
|
/* new main */
|
||||||
newmain = BKE_main_new();
|
newmain = BKE_main_new();
|
||||||
BLI_addtail(fd->mainlist, newmain);
|
BLI_addtail(fd->mainlist, newmain);
|
||||||
@@ -8017,15 +8030,33 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
|
|||||||
return blo_nextbhead(fd, bhead);
|
return blo_nextbhead(fd, bhead);
|
||||||
|
|
||||||
id->tag = tag | LIB_TAG_NEED_LINK;
|
id->tag = tag | LIB_TAG_NEED_LINK;
|
||||||
|
printf("id: %s (%p, %p), lib: %p\n", id->name, id, id->uuid, main->curlib);
|
||||||
id->lib = main->curlib;
|
id->lib = main->curlib;
|
||||||
id->us = ID_FAKE_USERS(id);
|
id->us = ID_FAKE_USERS(id);
|
||||||
id->icon_id = 0;
|
id->icon_id = 0;
|
||||||
|
|
||||||
/* this case cannot be direct_linked: it's just the ID part */
|
/* this case cannot be direct_linked: it's just the ID part */
|
||||||
if (bhead->code == ID_ID) {
|
if (bhead->code == ID_ID) {
|
||||||
|
if (id->uuid) {
|
||||||
|
/* read all data into fd->datamap */
|
||||||
|
bhead = read_data_into_oldnewmap(fd, bhead, __func__);
|
||||||
|
|
||||||
|
id->uuid = newdataadr(fd, id->uuid);
|
||||||
|
|
||||||
|
oldnewmap_free_unused(fd->datamap);
|
||||||
|
oldnewmap_clear(fd->datamap);
|
||||||
|
return bhead;
|
||||||
|
}
|
||||||
|
|
||||||
return blo_nextbhead(fd, bhead);
|
return blo_nextbhead(fd, bhead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we have a real ID from a virtual library, tag ID as extern. */
|
||||||
|
if (id->lib && (id->lib->flag & LIBRARY_FLAG_VIRTUAL)) {
|
||||||
|
BLI_assert(ID_VIRTUAL_LIBRARY_VALID(id));
|
||||||
|
id->tag |= LIB_TAG_EXTERN;
|
||||||
|
}
|
||||||
|
|
||||||
/* need a name for the mallocN, just for debugging and sane prints on leaks */
|
/* need a name for the mallocN, just for debugging and sane prints on leaks */
|
||||||
allocname = dataname(GS(id->name));
|
allocname = dataname(GS(id->name));
|
||||||
|
|
||||||
@@ -8472,7 +8503,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
|
|||||||
bhead->code = ID_SCR;
|
bhead->code = ID_SCR;
|
||||||
/* deliberate pass on to default */
|
/* deliberate pass on to default */
|
||||||
default:
|
default:
|
||||||
bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
|
bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_LOCAL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8491,6 +8522,8 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
|
|||||||
lib_verify_nodetree(bfd->main, true);
|
lib_verify_nodetree(bfd->main, true);
|
||||||
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
|
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
|
||||||
|
|
||||||
|
BKE_libraries_asset_repositories_rebuild(bfd->main);
|
||||||
|
|
||||||
link_global(fd, bfd); /* as last */
|
link_global(fd, bfd); /* as last */
|
||||||
|
|
||||||
fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */
|
fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */
|
||||||
@@ -9827,8 +9860,10 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ID *link_named_part_ex(
|
static ID *link_named_part_ex(
|
||||||
Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
|
Main *mainl, FileData *fd, const AssetEngineType *aet, const char *root,
|
||||||
Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
|
const short idcode, const char *name, const AssetUUID *uuid, const int flag,
|
||||||
|
Scene *scene, View3D *v3d,
|
||||||
|
const bool use_placeholders, const bool force_indirect)
|
||||||
{
|
{
|
||||||
ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
|
ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
|
||||||
|
|
||||||
@@ -9841,6 +9876,18 @@ static ID *link_named_part_ex(
|
|||||||
id->tag |= LIB_TAG_DOIT;
|
id->tag |= LIB_TAG_DOIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id && uuid) {
|
||||||
|
BLI_assert(root);
|
||||||
|
|
||||||
|
id->uuid = MEM_mallocN(sizeof(*id->uuid), __func__);
|
||||||
|
*id->uuid = *uuid;
|
||||||
|
id->flag |= LIB_ASSET;
|
||||||
|
|
||||||
|
if (!mainl->curlib->asset_repository) {
|
||||||
|
BKE_library_asset_repository_init(mainl->curlib, aet, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9881,7 +9928,33 @@ ID *BLO_library_link_named_part_ex(
|
|||||||
const bool use_placeholders, const bool force_indirect)
|
const bool use_placeholders, const bool force_indirect)
|
||||||
{
|
{
|
||||||
FileData *fd = (FileData*)(*bh);
|
FileData *fd = (FileData*)(*bh);
|
||||||
return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect);
|
return link_named_part_ex(mainl, fd, NULL, NULL, idcode, name, NULL, flag, scene, v3d, use_placeholders, force_indirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a named datablock from an external blend file, using given asset engine & asset UUID.
|
||||||
|
* Optionally instantiate the object/group in the scene when the flags are set.
|
||||||
|
*
|
||||||
|
* \param mainl The main database to link from (not the active one).
|
||||||
|
* \param bh The blender file handle.
|
||||||
|
* \param aet The asset engine type (NULL when no asset engine is used).
|
||||||
|
* \param root the 'path' of the asset repository.
|
||||||
|
* \param idcode The kind of datablock to link.
|
||||||
|
* \param name The name of the datablock (without the 2 char ID prefix).
|
||||||
|
* \param uuid The asset engine's UUID of this datablock (NULL when no asset engine is used).
|
||||||
|
* \param flag Options for linking, used for instantiating.
|
||||||
|
* \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
|
||||||
|
* \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
|
||||||
|
* \return the linked ID when found.
|
||||||
|
*/
|
||||||
|
struct ID *BLO_library_link_named_part_asset(
|
||||||
|
Main *mainl, BlendHandle **bh, const AssetEngineType *aet, const char *root,
|
||||||
|
const short idcode, const char *name, const AssetUUID *uuid, const short flag,
|
||||||
|
Scene *scene, View3D *v3d,
|
||||||
|
const bool use_placeholders, const bool force_indirect)
|
||||||
|
{
|
||||||
|
FileData *fd = (FileData*)(*bh);
|
||||||
|
return link_named_part_ex(mainl, fd, aet, root, idcode, name, uuid, flag, scene, v3d, use_placeholders, force_indirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
|
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
|
||||||
@@ -10019,6 +10092,8 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
|
|||||||
/* clear group instantiating tag */
|
/* clear group instantiating tag */
|
||||||
BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
|
BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
|
||||||
|
|
||||||
|
BKE_libraries_asset_repositories_rebuild(mainvar);
|
||||||
|
|
||||||
/* patch to prevent switch_endian happens twice */
|
/* patch to prevent switch_endian happens twice */
|
||||||
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
|
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
|
||||||
blo_freefiledata(*fd);
|
blo_freefiledata(*fd);
|
||||||
@@ -10195,6 +10270,11 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
|
|||||||
* (known case: some directly linked shapekey from a missing lib...). */
|
* (known case: some directly linked shapekey from a missing lib...). */
|
||||||
/* BLI_assert(realid != NULL); */
|
/* BLI_assert(realid != NULL); */
|
||||||
|
|
||||||
|
if (realid && id->uuid) {
|
||||||
|
/* we can give ownership of that pointer to new ID. */
|
||||||
|
realid->uuid = id->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
change_idid_adr(mainlist, basefd, id, realid);
|
change_idid_adr(mainlist, basefd, id, realid);
|
||||||
|
|
||||||
MEM_freeN(id);
|
MEM_freeN(id);
|
||||||
|
@@ -672,7 +672,14 @@ static void write_iddata(void *wd, const ID *id)
|
|||||||
{
|
{
|
||||||
/* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
|
/* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
|
||||||
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
|
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
|
||||||
IDP_WriteProperty(id->properties, wd);
|
/* We want to write IDProps from 'virtual' libraries too, but not from 'real' linked datablocks... */
|
||||||
|
if (!id->uuid || (id->lib && (id->lib->flag & LIBRARY_FLAG_VIRTUAL))) {
|
||||||
|
IDP_WriteProperty(id->properties, wd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id->uuid) {
|
||||||
|
BLI_assert(id->lib && id->lib->asset_repository);
|
||||||
|
writestruct(wd, DATA, AssetUUID, 1, id->uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3871,6 +3878,7 @@ static void write_libraries(WriteData *wd, Main *main)
|
|||||||
bool found_one;
|
bool found_one;
|
||||||
|
|
||||||
for (; main; main = main->next) {
|
for (; main; main = main->next) {
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->library));
|
||||||
|
|
||||||
a = tot = set_listbasepointers(main, lbarray);
|
a = tot = set_listbasepointers(main, lbarray);
|
||||||
|
|
||||||
@@ -3900,6 +3908,9 @@ static void write_libraries(WriteData *wd, Main *main)
|
|||||||
writestruct(wd, ID_LI, Library, 1, main->curlib);
|
writestruct(wd, ID_LI, Library, 1, main->curlib);
|
||||||
write_iddata(wd, &main->curlib->id);
|
write_iddata(wd, &main->curlib->id);
|
||||||
|
|
||||||
|
BLI_assert(!(main->curlib->flag & LIBRARY_FLAG_VIRTUAL) ||
|
||||||
|
(!main->curlib->packedfile && main->curlib->asset_repository));
|
||||||
|
|
||||||
if (main->curlib->packedfile) {
|
if (main->curlib->packedfile) {
|
||||||
PackedFile *pf = main->curlib->packedfile;
|
PackedFile *pf = main->curlib->packedfile;
|
||||||
writestruct(wd, DATA, PackedFile, 1, pf);
|
writestruct(wd, DATA, PackedFile, 1, pf);
|
||||||
@@ -3909,15 +3920,57 @@ static void write_libraries(WriteData *wd, Main *main)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (a--) {
|
if (main->curlib->asset_repository) {
|
||||||
for (id = lbarray[a]->first; id; id = id->next) {
|
writestruct(wd, DATA, AssetRepositoryRef, 1, main->curlib->asset_repository);
|
||||||
if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
|
}
|
||||||
if (!BKE_idcode_is_linkable(GS(id->name))) {
|
|
||||||
printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
|
if (main->curlib->flag & LIBRARY_FLAG_VIRTUAL) {
|
||||||
"but is flagged as directly linked", id->name, main->curlib->filepath);
|
/* Those should be the only datatypes found in a virtual library! */
|
||||||
BLI_assert(0);
|
write_images (wd, &main->image);
|
||||||
|
write_vfonts (wd, &main->vfont);
|
||||||
|
write_texts (wd, &main->text);
|
||||||
|
write_sounds (wd, &main->sound);
|
||||||
|
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->wm));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->screen));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->movieclip));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->mask));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->scene));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->curve));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->mball));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->camera));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->lamp));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->latt));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->key));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->world));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->speaker));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->group));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->armature));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->action));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->object));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->mat));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->tex));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->mesh));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->particle));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->nodetree));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->brush));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->palettes));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->paintcurves));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->gpencil));
|
||||||
|
BLI_assert(BLI_listbase_is_empty(&main->linestyle));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (a--) {
|
||||||
|
for (id = lbarray[a]->first; id; id = id->next) {
|
||||||
|
if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
|
||||||
|
if (!BKE_idcode_is_linkable(GS(id->name))) {
|
||||||
|
printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
|
||||||
|
"but is flagged as directly linked", id->name, main->curlib->filepath);
|
||||||
|
BLI_assert(0);
|
||||||
|
}
|
||||||
|
writestruct(wd, ID_ID, ID, 1, id);
|
||||||
|
write_iddata(wd, id);
|
||||||
}
|
}
|
||||||
writestruct(wd, ID_ID, ID, 1, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#define __ED_FILESELECT_H__
|
#define __ED_FILESELECT_H__
|
||||||
|
|
||||||
struct ARegion;
|
struct ARegion;
|
||||||
|
struct AssetEngine;
|
||||||
struct FileSelectParams;
|
struct FileSelectParams;
|
||||||
struct ScrArea;
|
struct ScrArea;
|
||||||
struct SpaceFile;
|
struct SpaceFile;
|
||||||
@@ -111,6 +112,8 @@ void ED_file_read_bookmarks(void);
|
|||||||
|
|
||||||
void ED_file_change_dir(struct bContext *C);
|
void ED_file_change_dir(struct bContext *C);
|
||||||
|
|
||||||
|
struct AssetEngine *ED_filelist_assetengine_get(struct SpaceFile *sfile);
|
||||||
|
|
||||||
/* File menu stuff */
|
/* File menu stuff */
|
||||||
|
|
||||||
typedef enum FSMenuCategory {
|
typedef enum FSMenuCategory {
|
||||||
|
@@ -459,6 +459,11 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
|
|||||||
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
|
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
|
||||||
data->totline++;
|
data->totline++;
|
||||||
}
|
}
|
||||||
|
else if (ID_IS_LINKED_DATAPATH(id)) {
|
||||||
|
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Using file path as asset"));
|
||||||
|
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
|
||||||
|
data->totline++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (but->optype) {
|
else if (but->optype) {
|
||||||
|
@@ -521,7 +521,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
|
|||||||
const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
|
const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
|
||||||
const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
|
const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
|
||||||
|
|
||||||
numfiles = filelist_files_ensure(files);
|
numfiles = filelist_files_ensure(files, params);
|
||||||
|
|
||||||
if (params->display != FILE_IMGDISPLAY) {
|
if (params->display != FILE_IMGDISPLAY) {
|
||||||
|
|
||||||
|
@@ -109,11 +109,10 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
|
|||||||
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my);
|
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my);
|
||||||
|
|
||||||
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
|
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
|
||||||
void file_sfile_to_operator_ex(struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
|
void file_sfile_to_operator_ex(struct wmOperator *op, struct SpaceFile *sfile, char *filepath, const bool is_fake);
|
||||||
void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile);
|
void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile);
|
||||||
void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
|
void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
|
||||||
|
|
||||||
|
|
||||||
/* filesel.c */
|
/* filesel.c */
|
||||||
void fileselect_file_set(SpaceFile *sfile, const int index);
|
void fileselect_file_set(SpaceFile *sfile, const int index);
|
||||||
float file_string_width(const char *str);
|
float file_string_width(const char *str);
|
||||||
|
@@ -33,9 +33,14 @@
|
|||||||
#include "BLI_fileops_types.h"
|
#include "BLI_fileops_types.h"
|
||||||
#include "BLI_linklist.h"
|
#include "BLI_linklist.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_define.h"
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
#include "BLO_readfile.h"
|
#include "BLO_readfile.h"
|
||||||
|
|
||||||
#include "BKE_appdir.h"
|
#include "BKE_appdir.h"
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_screen.h"
|
#include "BKE_screen.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
@@ -53,9 +58,6 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
#include "RNA_define.h"
|
|
||||||
|
|
||||||
#include "UI_view2d.h"
|
#include "UI_view2d.h"
|
||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
@@ -100,7 +102,7 @@ static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
|
|||||||
{
|
{
|
||||||
FileSelection sel;
|
FileSelection sel;
|
||||||
sel.first = 0;
|
sel.first = 0;
|
||||||
sel.last = filelist_files_ensure(sfile->files) - 1;
|
sel.last = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile)) - 1;
|
||||||
|
|
||||||
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
|
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
|
||||||
}
|
}
|
||||||
@@ -140,7 +142,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
|
|||||||
{
|
{
|
||||||
ARegion *ar = CTX_wm_region(C);
|
ARegion *ar = CTX_wm_region(C);
|
||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
FileSelection sel;
|
FileSelection sel;
|
||||||
|
|
||||||
sel = find_file_mouse_rect(sfile, ar, rect);
|
sel = find_file_mouse_rect(sfile, ar, rect);
|
||||||
@@ -169,7 +171,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
|
|||||||
FileSelect retval = FILE_SELECT_NOTHING;
|
FileSelect retval = FILE_SELECT_NOTHING;
|
||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
const FileDirEntry *file;
|
const FileDirEntry *file;
|
||||||
|
|
||||||
/* make the selected file active */
|
/* make the selected file active */
|
||||||
@@ -223,9 +225,8 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
|
|||||||
/**
|
/**
|
||||||
* \warning: loops over all files so better use cautiously
|
* \warning: loops over all files so better use cautiously
|
||||||
*/
|
*/
|
||||||
static bool file_is_any_selected(struct FileList *files)
|
static bool file_is_any_selected(struct FileList *files, const int numfiles)
|
||||||
{
|
{
|
||||||
const int numfiles = filelist_files_ensure(files);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Is any file selected ? */
|
/* Is any file selected ? */
|
||||||
@@ -288,7 +289,8 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
|
|||||||
FileSelect retval = FILE_SELECT_NOTHING;
|
FileSelect retval = FILE_SELECT_NOTHING;
|
||||||
FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
|
FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
|
||||||
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
|
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
|
||||||
|
const int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
|
|
||||||
/* flag the files as selected in the filelist */
|
/* flag the files as selected in the filelist */
|
||||||
filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
|
filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
|
||||||
|
|
||||||
@@ -303,7 +305,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
|
if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files, numfiles)) {
|
||||||
sfile->params->active_file = -1;
|
sfile->params->active_file = -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -483,7 +485,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
|
|
||||||
if (sfile && sfile->params) {
|
if (sfile && sfile->params) {
|
||||||
int idx = sfile->params->highlight_file;
|
int idx = sfile->params->highlight_file;
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
|
|
||||||
if ((idx >= 0) && (idx < numfiles)) {
|
if ((idx >= 0) && (idx < numfiles)) {
|
||||||
/* single select, deselect all selected first */
|
/* single select, deselect all selected first */
|
||||||
@@ -648,8 +650,8 @@ static bool file_walk_select_do(
|
|||||||
const bool extend, const bool fill)
|
const bool extend, const bool fill)
|
||||||
{
|
{
|
||||||
struct FileList *files = sfile->files;
|
struct FileList *files = sfile->files;
|
||||||
const int numfiles = filelist_files_ensure(files);
|
const int numfiles = filelist_files_ensure(files, ED_fileselect_get_params(sfile));
|
||||||
const bool has_selection = file_is_any_selected(files);
|
const bool has_selection = file_is_any_selected(files, numfiles);
|
||||||
const int active_old = params->active_file;
|
const int active_old = params->active_file;
|
||||||
int active_new = -1;
|
int active_new = -1;
|
||||||
int other_site = -1; /* file on the other site of active_old */
|
int other_site = -1; /* file on the other site of active_old */
|
||||||
@@ -764,8 +766,8 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
|
|||||||
ScrArea *sa = CTX_wm_area(C);
|
ScrArea *sa = CTX_wm_area(C);
|
||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
FileSelection sel;
|
FileSelection sel;
|
||||||
const int numfiles = filelist_files_ensure(sfile->files);
|
const int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
const bool has_selection = file_is_any_selected(sfile->files);
|
const bool has_selection = file_is_any_selected(sfile->files, numfiles);
|
||||||
|
|
||||||
sel.first = 0;
|
sel.first = 0;
|
||||||
sel.last = numfiles - 1;
|
sel.last = numfiles - 1;
|
||||||
@@ -1101,8 +1103,8 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
|
|||||||
|
|
||||||
if (sfile == NULL || sfile->files == NULL) return 0;
|
if (sfile == NULL || sfile->files == NULL) return 0;
|
||||||
|
|
||||||
numfiles = filelist_files_ensure(sfile->files);
|
|
||||||
params = ED_fileselect_get_params(sfile);
|
params = ED_fileselect_get_params(sfile);
|
||||||
|
numfiles = filelist_files_ensure(sfile->files, params);
|
||||||
|
|
||||||
origfile = params->highlight_file;
|
origfile = params->highlight_file;
|
||||||
|
|
||||||
@@ -1189,81 +1191,146 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath)
|
void file_sfile_to_operator_ex(
|
||||||
|
wmOperator *op, SpaceFile *sfile, char filepath[FILE_MAX_LIBEXTRA], const bool is_fake)
|
||||||
{
|
{
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop, *prop_files, *prop_dirs;
|
||||||
|
/* Note filebrowser does not create ae for default NONE 'engine', we'll get NULL in this case here. */
|
||||||
|
AssetEngine *ae = filelist_assetengine_get(sfile->files);
|
||||||
|
AssetUUIDList *uuids;
|
||||||
|
FileDirEntryArr *selection;
|
||||||
|
FileCheckType check = CHECK_NONE;
|
||||||
|
|
||||||
BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
|
if ((prop_files = RNA_struct_find_property(op->ptr, "files"))) {
|
||||||
|
check |= CHECK_FILES;
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
|
}
|
||||||
if (RNA_property_boolean_get(op->ptr, prop)) {
|
if ((prop_dirs = RNA_struct_find_property(op->ptr, "dirs"))) {
|
||||||
BLI_path_rel(filepath, G.main->name);
|
check |= CHECK_DIRS;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
|
BLI_assert(STREQ(sfile->params->dir, filelist_dir(sfile->files)));
|
||||||
RNA_property_string_set(op->ptr, prop, sfile->params->file);
|
|
||||||
|
selection = filelist_selection_get(sfile->files, check, sfile->params->file, &uuids, !is_fake);
|
||||||
|
|
||||||
|
if (ae && selection->nbr_entries && !is_fake) { /* We only expect uuids when not is_fake... */
|
||||||
|
BLI_assert(uuids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
|
if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
|
||||||
RNA_property_string_set(op->ptr, prop, sfile->params->dir);
|
RNA_property_string_set(op->ptr, prop, selection->root);
|
||||||
}
|
}
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
|
|
||||||
RNA_property_string_set(op->ptr, prop, filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* some ops have multiple files to select */
|
|
||||||
/* this is called on operators check() so clear collections first since
|
|
||||||
* they may be already set. */
|
|
||||||
{
|
|
||||||
int i, numfiles = filelist_files_ensure(sfile->files);
|
|
||||||
|
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
|
if (selection->nbr_entries != 0) {
|
||||||
PointerRNA itemptr;
|
const char *filename;
|
||||||
int num_files = 0;
|
|
||||||
RNA_property_collection_clear(op->ptr, prop);
|
filename = ((FileDirEntry *)selection->entries.first)->relpath;
|
||||||
for (i = 0; i < numfiles; i++) {
|
BLI_join_dirfile(filepath, FILE_MAX_LIBEXTRA /* XXX sizeof(filepath) */, selection->root, filename);
|
||||||
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
|
|
||||||
FileDirEntry *file = filelist_file(sfile->files, i);
|
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
|
||||||
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
if (RNA_property_boolean_get(op->ptr, prop)) {
|
||||||
RNA_string_set(&itemptr, "name", file->relpath);
|
BLI_path_rel(filepath, G.main->name);
|
||||||
num_files++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* make sure the file specified in the filename button is added even if no files selected */
|
|
||||||
if (0 == num_files) {
|
|
||||||
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
|
||||||
RNA_string_set(&itemptr, "name", sfile->params->file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
|
if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
|
||||||
PointerRNA itemptr;
|
RNA_property_string_set(op->ptr, prop, filename);
|
||||||
int num_dirs = 0;
|
}
|
||||||
RNA_property_collection_clear(op->ptr, prop);
|
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
|
||||||
for (i = 0; i < numfiles; i++) {
|
RNA_property_string_set(op->ptr, prop, filepath);
|
||||||
if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) {
|
}
|
||||||
FileDirEntry *file = filelist_file(sfile->files, i);
|
if (ae && uuids) {
|
||||||
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
if ((prop = RNA_struct_find_property(op->ptr, "asset_uuid"))) {
|
||||||
RNA_string_set(&itemptr, "name", file->relpath);
|
RNA_property_int_set_array(op->ptr, prop, uuids->uuids[0].uuid_asset);
|
||||||
num_dirs++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if ((prop = RNA_struct_find_property(op->ptr, "variant_uuid"))) {
|
||||||
/* make sure the directory specified in the button is added even if no directory selected */
|
RNA_property_int_set_array(op->ptr, prop, uuids->uuids[0].uuid_variant);
|
||||||
if (0 == num_dirs) {
|
}
|
||||||
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
if ((prop = RNA_struct_find_property(op->ptr, "revision_uuid"))) {
|
||||||
RNA_string_set(&itemptr, "name", sfile->params->dir);
|
RNA_property_int_set_array(op->ptr, prop, uuids->uuids[0].uuid_revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* some ops have multiple files to select */
|
||||||
|
/* this is called on operators check() so clear collections first since
|
||||||
|
* they may be already set. */
|
||||||
|
{
|
||||||
|
if (prop_files) {
|
||||||
|
FileDirEntry *entry;
|
||||||
|
PointerRNA itemptr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
RNA_property_collection_clear(op->ptr, prop_files);
|
||||||
|
for (i = 0, entry = selection->entries.first; entry; entry = entry->next, i++) {
|
||||||
|
if (!(entry->typeflag & FILE_TYPE_DIR)) {
|
||||||
|
RNA_property_collection_add(op->ptr, prop_files, &itemptr);
|
||||||
|
RNA_string_set(&itemptr, "name", entry->relpath);
|
||||||
|
if (ae) {
|
||||||
|
BLI_assert(i < uuids->nbr_uuids);
|
||||||
|
RNA_int_set_array(&itemptr, "asset_uuid", uuids->uuids[i].uuid_asset);
|
||||||
|
RNA_int_set_array(&itemptr, "variant_uuid", uuids->uuids[i].uuid_variant);
|
||||||
|
RNA_int_set_array(&itemptr, "revision_uuid", uuids->uuids[i].uuid_revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop_dirs) {
|
||||||
|
FileDirEntry *entry;
|
||||||
|
PointerRNA itemptr;
|
||||||
|
int num_dirs = 0;
|
||||||
|
|
||||||
|
RNA_property_collection_clear(op->ptr, prop);
|
||||||
|
for (entry = selection->entries.first; entry; entry = entry->next) {
|
||||||
|
if (entry->typeflag & FILE_TYPE_DIR) {
|
||||||
|
RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
|
||||||
|
RNA_string_set(&itemptr, "name", entry->relpath);
|
||||||
|
num_dirs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure the directory specified in the button is added even if no directory selected */
|
||||||
|
if (!num_dirs) {
|
||||||
|
RNA_property_collection_add(op->ptr, prop_dirs, &itemptr);
|
||||||
|
RNA_string_set(&itemptr, "name", sfile->params->dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* We have to ensure those are properly reset!!! */
|
||||||
|
if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
|
||||||
|
RNA_property_string_set(op->ptr, prop, sfile->params->file);
|
||||||
|
}
|
||||||
|
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
|
||||||
|
BLI_join_dirfile(filepath, FILE_MAX_LIBEXTRA, sfile->params->dir, sfile->params->file);
|
||||||
|
RNA_property_string_set(op->ptr, prop, filepath);
|
||||||
|
}
|
||||||
|
if (prop_files) {
|
||||||
|
RNA_property_reset(op->ptr, prop, 0);
|
||||||
|
}
|
||||||
|
if (prop_dirs) {
|
||||||
|
RNA_property_reset(op->ptr, prop, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_fake && ae && (prop = RNA_struct_find_property(op->ptr, "asset_engine"))) {
|
||||||
|
RNA_property_string_set(op->ptr, prop, ae->type->idname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuids) {
|
||||||
|
MEM_freeN(uuids->uuids);
|
||||||
|
MEM_freeN(uuids);
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_filedir_entryarr_clear(selection);
|
||||||
|
MEM_freeN(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile)
|
void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile)
|
||||||
{
|
{
|
||||||
char filepath[FILE_MAX];
|
char filepath[FILE_MAX];
|
||||||
|
|
||||||
file_sfile_to_operator_ex(op, sfile, filepath);
|
file_sfile_to_operator_ex(op, sfile, filepath, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
|
void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
|
||||||
@@ -1320,7 +1387,8 @@ void file_draw_check(bContext *C)
|
|||||||
wmOperator *op = sfile->op;
|
wmOperator *op = sfile->op;
|
||||||
if (op) { /* fail on reload */
|
if (op) { /* fail on reload */
|
||||||
if (op->type->check) {
|
if (op->type->check) {
|
||||||
file_sfile_to_operator(op, sfile);
|
char filepath[FILE_MAX_LIBEXTRA];
|
||||||
|
file_sfile_to_operator_ex(op, sfile, filepath, true);
|
||||||
|
|
||||||
/* redraw */
|
/* redraw */
|
||||||
if (op->type->check(C, op)) {
|
if (op->type->check(C, op)) {
|
||||||
@@ -1362,8 +1430,8 @@ int file_exec(bContext *C, wmOperator *exec_op)
|
|||||||
wmWindowManager *wm = CTX_wm_manager(C);
|
wmWindowManager *wm = CTX_wm_manager(C);
|
||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
|
const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
|
||||||
char filepath[FILE_MAX];
|
char filepath[FILE_MAX_LIBEXTRA];
|
||||||
|
|
||||||
/* directory change */
|
/* directory change */
|
||||||
if (file && (file->typeflag & FILE_TYPE_DIR)) {
|
if (file && (file->typeflag & FILE_TYPE_DIR)) {
|
||||||
if (!file->relpath) {
|
if (!file->relpath) {
|
||||||
@@ -1388,7 +1456,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
|
|||||||
/* when used as a macro, for doubleclick,
|
/* when used as a macro, for doubleclick,
|
||||||
* to prevent closing when doubleclicking on .. item */
|
* to prevent closing when doubleclicking on .. item */
|
||||||
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
|
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
|
||||||
const int numfiles = filelist_files_ensure(sfile->files);
|
const int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
int i, active = 0;
|
int i, active = 0;
|
||||||
|
|
||||||
for (i = 0; i < numfiles; i++) {
|
for (i = 0; i < numfiles; i++) {
|
||||||
@@ -1403,7 +1471,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
|
|||||||
|
|
||||||
sfile->op = NULL;
|
sfile->op = NULL;
|
||||||
|
|
||||||
file_sfile_to_operator_ex(op, sfile, filepath);
|
file_sfile_to_operator_ex(op, sfile, filepath, false);
|
||||||
|
|
||||||
if (BLI_exists(sfile->params->dir)) {
|
if (BLI_exists(sfile->params->dir)) {
|
||||||
fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
|
fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
|
||||||
@@ -1572,7 +1640,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
|
|||||||
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
|
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata)
|
||||||
return OPERATOR_PASS_THROUGH;
|
return OPERATOR_PASS_THROUGH;
|
||||||
|
|
||||||
numfiles = filelist_files_ensure(sfile->files);
|
numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
|
|
||||||
/* check if we are editing a name */
|
/* check if we are editing a name */
|
||||||
for (i = 0; i < numfiles; ++i) {
|
for (i = 0; i < numfiles; ++i) {
|
||||||
@@ -2169,7 +2237,7 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
|
|||||||
|
|
||||||
if (sfile->params) {
|
if (sfile->params) {
|
||||||
int idx = sfile->params->highlight_file;
|
int idx = sfile->params->highlight_file;
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, sfile->params);
|
||||||
if ((0 <= idx) && (idx < numfiles)) {
|
if ((0 <= idx) && (idx < numfiles)) {
|
||||||
FileDirEntry *file = filelist_file(sfile->files, idx);
|
FileDirEntry *file = filelist_file(sfile->files, idx);
|
||||||
filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
|
filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
|
||||||
@@ -2190,7 +2258,7 @@ static int file_rename_poll(bContext *C)
|
|||||||
|
|
||||||
if (sfile && sfile->params) {
|
if (sfile && sfile->params) {
|
||||||
int idx = sfile->params->highlight_file;
|
int idx = sfile->params->highlight_file;
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, sfile->params);
|
||||||
|
|
||||||
if ((0 <= idx) && (idx < numfiles)) {
|
if ((0 <= idx) && (idx < numfiles)) {
|
||||||
FileDirEntry *file = filelist_file(sfile->files, idx);
|
FileDirEntry *file = filelist_file(sfile->files, idx);
|
||||||
@@ -2236,7 +2304,7 @@ static int file_delete_poll(bContext *C)
|
|||||||
|
|
||||||
if (sfile && sfile->params) {
|
if (sfile && sfile->params) {
|
||||||
char dir[FILE_MAX];
|
char dir[FILE_MAX];
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, sfile->params);
|
||||||
int i;
|
int i;
|
||||||
int num_selected = 0;
|
int num_selected = 0;
|
||||||
|
|
||||||
@@ -2263,7 +2331,7 @@ int file_delete_exec(bContext *C, wmOperator *op)
|
|||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
ScrArea *sa = CTX_wm_area(C);
|
ScrArea *sa = CTX_wm_area(C);
|
||||||
FileDirEntry *file;
|
FileDirEntry *file;
|
||||||
int numfiles = filelist_files_ensure(sfile->files);
|
int numfiles = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bool report_error = false;
|
bool report_error = false;
|
||||||
|
@@ -63,6 +63,9 @@
|
|||||||
# include "BLI_winstuff.h"
|
# include "BLI_winstuff.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
#include "BKE_library.h"
|
#include "BKE_library.h"
|
||||||
@@ -285,6 +288,8 @@ enum {
|
|||||||
typedef struct FileList {
|
typedef struct FileList {
|
||||||
FileDirEntryArr filelist;
|
FileDirEntryArr filelist;
|
||||||
|
|
||||||
|
AssetEngine *ae;
|
||||||
|
|
||||||
short prv_w;
|
short prv_w;
|
||||||
short prv_h;
|
short prv_h;
|
||||||
|
|
||||||
@@ -509,30 +514,17 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void
|
|||||||
return BLI_natstrcmp(name1, name2);
|
return BLI_natstrcmp(name1, name2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filelist_sort(struct FileList *filelist)
|
static bool filelist_need_sorting(struct FileList *filelist)
|
||||||
{
|
{
|
||||||
if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) {
|
return (((filelist->flags & FL_NEED_SORTING) || (filelist->ae && (filelist->ae->flag & AE_DIRTY_SORTING))) &&
|
||||||
switch (filelist->sort) {
|
(filelist->sort != FILE_SORT_NONE));
|
||||||
case FILE_SORT_ALPHA:
|
}
|
||||||
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
|
|
||||||
break;
|
|
||||||
case FILE_SORT_TIME:
|
|
||||||
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
|
|
||||||
break;
|
|
||||||
case FILE_SORT_SIZE:
|
|
||||||
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
|
|
||||||
break;
|
|
||||||
case FILE_SORT_EXTENSION:
|
|
||||||
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
|
|
||||||
break;
|
|
||||||
case FILE_SORT_NONE: /* Should never reach this point! */
|
|
||||||
default:
|
|
||||||
BLI_assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
filelist_filter_clear(filelist);
|
static void filelist_need_sorting_clear(struct FileList *filelist)
|
||||||
filelist->flags &= ~FL_NEED_SORTING;
|
{
|
||||||
|
filelist->flags &= ~FL_NEED_SORTING;
|
||||||
|
if (filelist->ae) {
|
||||||
|
filelist->ae->flag &= ~AE_DIRTY_SORTING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,54 +670,17 @@ static void filelist_filter_clear(FileList *filelist)
|
|||||||
filelist->flags |= FL_NEED_FILTERING;
|
filelist->flags |= FL_NEED_FILTERING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filelist_filter(FileList *filelist)
|
static bool filelist_need_filtering(struct FileList *filelist)
|
||||||
{
|
{
|
||||||
int num_filtered = 0;
|
return ((filelist->flags & FL_NEED_FILTERING) || (filelist->ae && (filelist->ae->flag & AE_DIRTY_FILTER)));
|
||||||
const int num_files = filelist->filelist.nbr_entries;
|
}
|
||||||
FileListInternEntry **filtered_tmp, *file;
|
|
||||||
|
|
||||||
if (filelist->filelist.nbr_entries == 0) {
|
static void filelist_need_filtering_clear(struct FileList *filelist)
|
||||||
return;
|
{
|
||||||
}
|
|
||||||
|
|
||||||
if (!(filelist->flags & FL_NEED_FILTERING)) {
|
|
||||||
/* Assume it has already been filtered, nothing else to do! */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR;
|
|
||||||
if (filelist->max_recursion) {
|
|
||||||
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
|
|
||||||
* root path is a blend file. */
|
|
||||||
char dir[FILE_MAX_LIBEXTRA];
|
|
||||||
if (!filelist_islibrary(filelist, dir, NULL)) {
|
|
||||||
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
|
|
||||||
|
|
||||||
/* Filter remap & count how many files are left after filter in a single loop. */
|
|
||||||
for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
|
|
||||||
if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) {
|
|
||||||
filtered_tmp[num_filtered++] = file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filelist->filelist_intern.filtered) {
|
|
||||||
MEM_freeN(filelist->filelist_intern.filtered);
|
|
||||||
}
|
|
||||||
filelist->filelist_intern.filtered = MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered,
|
|
||||||
__func__);
|
|
||||||
memcpy(filelist->filelist_intern.filtered, filtered_tmp,
|
|
||||||
sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
|
|
||||||
filelist->filelist.nbr_entries_filtered = num_filtered;
|
|
||||||
// printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries);
|
|
||||||
|
|
||||||
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
|
|
||||||
filelist->flags &= ~FL_NEED_FILTERING;
|
filelist->flags &= ~FL_NEED_FILTERING;
|
||||||
|
if (filelist->ae) {
|
||||||
MEM_freeN(filtered_tmp);
|
filelist->ae->flag &= ~AE_DIRTY_FILTER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
|
void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
|
||||||
@@ -763,6 +718,93 @@ void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void filelist_sort_filter(struct FileList *filelist, FileSelectParams *params)
|
||||||
|
{
|
||||||
|
if (filelist->ae) {
|
||||||
|
if (filelist->ae->type->sort_filter) {
|
||||||
|
const bool need_sorting = filelist_need_sorting(filelist);
|
||||||
|
const bool need_filtering = filelist_need_filtering(filelist);
|
||||||
|
const bool changed = filelist->ae->type->sort_filter(
|
||||||
|
filelist->ae, need_sorting, need_filtering, params, &filelist->filelist);
|
||||||
|
// printf("%s: changed: %d (%d - %d)\n", __func__, changed, need_sorting, need_filtering);
|
||||||
|
if (changed) {
|
||||||
|
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (filelist_need_sorting(filelist)) {
|
||||||
|
switch (filelist->sort) {
|
||||||
|
case FILE_SORT_ALPHA:
|
||||||
|
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL);
|
||||||
|
break;
|
||||||
|
case FILE_SORT_TIME:
|
||||||
|
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL);
|
||||||
|
break;
|
||||||
|
case FILE_SORT_SIZE:
|
||||||
|
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL);
|
||||||
|
break;
|
||||||
|
case FILE_SORT_EXTENSION:
|
||||||
|
BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL);
|
||||||
|
break;
|
||||||
|
case FILE_SORT_NONE: /* Should never reach this point! */
|
||||||
|
default:
|
||||||
|
BLI_assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
filelist_filter_clear(filelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filelist_need_filtering(filelist)) {
|
||||||
|
int num_filtered = 0;
|
||||||
|
const int num_files = filelist->filelist.nbr_entries;
|
||||||
|
FileListInternEntry **filtered_tmp, *file;
|
||||||
|
|
||||||
|
if (filelist->filelist.nbr_entries == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR;
|
||||||
|
if (filelist->max_recursion) {
|
||||||
|
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
|
||||||
|
* root path is a blend file. */
|
||||||
|
char dir[FILE_MAXDIR];
|
||||||
|
if (!filelist_islibrary(filelist, dir, NULL)) {
|
||||||
|
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
|
||||||
|
|
||||||
|
/* Filter remap & count how many files are left after filter in a single loop. */
|
||||||
|
for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
|
||||||
|
if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) {
|
||||||
|
filtered_tmp[num_filtered++] = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filelist->filelist_intern.filtered) {
|
||||||
|
MEM_freeN(filelist->filelist_intern.filtered);
|
||||||
|
}
|
||||||
|
filelist->filelist_intern.filtered = MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered,
|
||||||
|
__func__);
|
||||||
|
memcpy(filelist->filelist_intern.filtered, filtered_tmp,
|
||||||
|
sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
|
||||||
|
filelist->filelist.nbr_entries_filtered = num_filtered;
|
||||||
|
// printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries);
|
||||||
|
|
||||||
|
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
|
||||||
|
|
||||||
|
MEM_freeN(filtered_tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filelist_need_sorting_clear(filelist);
|
||||||
|
filelist_need_filtering_clear(filelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ********** Icon/image helpers ********** */
|
/* ********** Icon/image helpers ********** */
|
||||||
|
|
||||||
void filelist_init_icons(void)
|
void filelist_init_icons(void)
|
||||||
@@ -940,17 +982,27 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
|
|||||||
|
|
||||||
/* ********** Main ********** */
|
/* ********** Main ********** */
|
||||||
|
|
||||||
static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir)
|
static void filelist_checkdir_dir(struct FileList *filelist, char *r_dir)
|
||||||
{
|
{
|
||||||
BLI_make_exist(r_dir);
|
if (filelist->ae && filelist->ae->type->check_dir) {
|
||||||
|
filelist->ae->type->check_dir(filelist->ae, r_dir);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_make_exist(r_dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
|
static void filelist_checkdir_lib(struct FileList *filelist, char *r_dir)
|
||||||
{
|
{
|
||||||
char dir[FILE_MAX_LIBEXTRA];
|
if (filelist->ae && filelist->ae->type->check_dir) {
|
||||||
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
|
filelist->ae->type->check_dir(filelist->ae, r_dir);
|
||||||
/* if not a valid library, we need it to be a valid directory! */
|
}
|
||||||
BLI_make_exist(r_dir);
|
else {
|
||||||
|
char dir[FILE_MAX_LIBEXTRA];
|
||||||
|
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
|
||||||
|
/* if not a valid library, we need it to be a valid directory! */
|
||||||
|
BLI_make_exist(r_dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,6 +1012,7 @@ static void filelist_checkdir_main(struct FileList *filelist, char *r_dir)
|
|||||||
filelist_checkdir_lib(filelist, r_dir);
|
filelist_checkdir_lib(filelist, r_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void filelist_entry_clear(FileDirEntry *entry)
|
static void filelist_entry_clear(FileDirEntry *entry)
|
||||||
{
|
{
|
||||||
if (entry->name) {
|
if (entry->name) {
|
||||||
@@ -1033,6 +1086,7 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
|
|||||||
array->entry_idx_start = -1;
|
array->entry_idx_start = -1;
|
||||||
array->entry_idx_end = -1;
|
array->entry_idx_end = -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void filelist_intern_entry_free(FileListInternEntry *entry)
|
static void filelist_intern_entry_free(FileListInternEntry *entry)
|
||||||
{
|
{
|
||||||
@@ -1216,9 +1270,11 @@ static void filelist_cache_free(FileListEntryCache *cache)
|
|||||||
|
|
||||||
BLI_ghash_free(cache->uuids, NULL, NULL);
|
BLI_ghash_free(cache->uuids, NULL, NULL);
|
||||||
|
|
||||||
|
// printf("\n\n%s:\n", __func__);
|
||||||
for (entry = cache->cached_entries.first; entry; entry = entry_next) {
|
for (entry = cache->cached_entries.first; entry; entry = entry_next) {
|
||||||
|
// printf("\t%s (%p, %p)\n", entry->relpath, entry, entry->next);
|
||||||
entry_next = entry->next;
|
entry_next = entry->next;
|
||||||
filelist_entry_free(entry);
|
BKE_filedir_entry_free(entry);
|
||||||
}
|
}
|
||||||
BLI_listbase_clear(&cache->cached_entries);
|
BLI_listbase_clear(&cache->cached_entries);
|
||||||
}
|
}
|
||||||
@@ -1249,9 +1305,11 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
|
|||||||
|
|
||||||
cache->size = new_size;
|
cache->size = new_size;
|
||||||
|
|
||||||
|
// printf("\n\n%s:\n", __func__);
|
||||||
for (entry = cache->cached_entries.first; entry; entry = entry_next) {
|
for (entry = cache->cached_entries.first; entry; entry = entry_next) {
|
||||||
|
// printf("\t%s (%p, %p)\n", entry->relpath, entry, entry->next);
|
||||||
entry_next = entry->next;
|
entry_next = entry->next;
|
||||||
filelist_entry_free(entry);
|
BKE_filedir_entry_free(entry);
|
||||||
}
|
}
|
||||||
BLI_listbase_clear(&cache->cached_entries);
|
BLI_listbase_clear(&cache->cached_entries);
|
||||||
}
|
}
|
||||||
@@ -1298,7 +1356,8 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const boo
|
|||||||
|
|
||||||
filelist_intern_free(&filelist->filelist_intern);
|
filelist_intern_free(&filelist->filelist_intern);
|
||||||
|
|
||||||
filelist_direntryarr_free(&filelist->filelist);
|
BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries));
|
||||||
|
BKE_filedir_entryarr_clear(&filelist->filelist);
|
||||||
|
|
||||||
if (do_selection && filelist->selection_state) {
|
if (do_selection && filelist->selection_state) {
|
||||||
BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL);
|
BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL);
|
||||||
@@ -1320,6 +1379,11 @@ void filelist_free(struct FileList *filelist)
|
|||||||
filelist_clear_ex(filelist, false, false); /* No need to clear cache & selection_state, we free them anyway. */
|
filelist_clear_ex(filelist, false, false); /* No need to clear cache & selection_state, we free them anyway. */
|
||||||
filelist_cache_free(&filelist->filelist_cache);
|
filelist_cache_free(&filelist->filelist_cache);
|
||||||
|
|
||||||
|
if (filelist->ae) {
|
||||||
|
BKE_asset_engine_free(filelist->ae);
|
||||||
|
filelist->ae = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (filelist->selection_state) {
|
if (filelist->selection_state) {
|
||||||
BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL);
|
BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL);
|
||||||
filelist->selection_state = NULL;
|
filelist->selection_state = NULL;
|
||||||
@@ -1338,6 +1402,11 @@ void filelist_freelib(struct FileList *filelist)
|
|||||||
filelist->libfiledata = NULL;
|
filelist->libfiledata = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssetEngine *filelist_assetengine_get(struct FileList *filelist)
|
||||||
|
{
|
||||||
|
return filelist->ae;
|
||||||
|
}
|
||||||
|
|
||||||
BlendHandle *filelist_lib(struct FileList *filelist)
|
BlendHandle *filelist_lib(struct FileList *filelist)
|
||||||
{
|
{
|
||||||
return filelist->libfiledata;
|
return filelist->libfiledata;
|
||||||
@@ -1371,6 +1440,30 @@ static const char *fileentry_uiname(const char *root, const char *relpath, const
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filelist_assetengine_set(struct FileList *filelist, struct AssetEngineType *aet)
|
||||||
|
{
|
||||||
|
if (filelist->ae) {
|
||||||
|
if (filelist->ae->type == aet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BKE_asset_engine_free(filelist->ae);
|
||||||
|
filelist->ae = NULL;
|
||||||
|
}
|
||||||
|
else if (!aet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aet) {
|
||||||
|
filelist->ae = BKE_asset_engine_create(aet, NULL);
|
||||||
|
}
|
||||||
|
filelist->flags |= FL_FORCE_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetEngine *ED_filelist_assetengine_get(SpaceFile *sfile)
|
||||||
|
{
|
||||||
|
return sfile->files->ae;
|
||||||
|
}
|
||||||
|
|
||||||
const char *filelist_dir(struct FileList *filelist)
|
const char *filelist_dir(struct FileList *filelist)
|
||||||
{
|
{
|
||||||
return filelist->filelist.root;
|
return filelist->filelist.root;
|
||||||
@@ -1388,6 +1481,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
|
|||||||
|
|
||||||
if (!STREQ(filelist->filelist.root, r_dir)) {
|
if (!STREQ(filelist->filelist.root, r_dir)) {
|
||||||
BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
|
BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
|
||||||
|
printf("%s: Forcing Reset!!!\n", __func__);
|
||||||
filelist->flags |= FL_FORCE_RESET;
|
filelist->flags |= FL_FORCE_RESET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1419,46 +1513,112 @@ bool filelist_pending(struct FileList *filelist)
|
|||||||
* Limited version of full update done by space_file's file_refresh(), to be used by operators and such.
|
* Limited version of full update done by space_file's file_refresh(), to be used by operators and such.
|
||||||
* Ensures given filelist is ready to be used (i.e. it is filtered and sorted), unless it is tagged for a full refresh.
|
* Ensures given filelist is ready to be used (i.e. it is filtered and sorted), unless it is tagged for a full refresh.
|
||||||
*/
|
*/
|
||||||
int filelist_files_ensure(FileList *filelist)
|
int filelist_files_ensure(FileList *filelist, FileSelectParams *params)
|
||||||
{
|
{
|
||||||
if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) {
|
if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) {
|
||||||
filelist_sort(filelist);
|
filelist_sort_filter(filelist, params);
|
||||||
filelist_filter(filelist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return filelist->filelist.nbr_entries_filtered;
|
return filelist->filelist.nbr_entries_filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static FileDirEntry *filelist_file_create_entries_block(FileList *filelist, const int index, const int size);
|
||||||
|
|
||||||
static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
|
static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
|
||||||
{
|
{
|
||||||
FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
|
|
||||||
FileListEntryCache *cache = &filelist->filelist_cache;
|
FileListEntryCache *cache = &filelist->filelist_cache;
|
||||||
FileDirEntry *ret;
|
FileDirEntry *ret;
|
||||||
FileDirEntryRevision *rev;
|
|
||||||
|
|
||||||
ret = MEM_callocN(sizeof(*ret), __func__);
|
if (filelist->ae) {
|
||||||
rev = MEM_callocN(sizeof(*rev), __func__);
|
ret = filelist_file_create_entries_block(filelist, index, 1);
|
||||||
|
|
||||||
rev->size = (uint64_t)entry->st.st_size;
|
BLI_assert(!ret || !ret->next);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
|
||||||
|
FileDirEntryRevision *rev;
|
||||||
|
|
||||||
rev->time = (int64_t)entry->st.st_mtime;
|
ret = MEM_callocN(sizeof(*ret), __func__);
|
||||||
|
rev = MEM_callocN(sizeof(*rev), __func__);
|
||||||
|
|
||||||
ret->entry = rev;
|
rev->size = (uint64_t)entry->st.st_size;
|
||||||
ret->relpath = BLI_strdup(entry->relpath);
|
|
||||||
ret->name = BLI_strdup(entry->name);
|
rev->time = (int64_t)entry->st.st_mtime;
|
||||||
ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath);
|
|
||||||
memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid));
|
ret->entry = rev;
|
||||||
ret->blentype = entry->blentype;
|
ret->relpath = BLI_strdup(entry->relpath);
|
||||||
ret->typeflag = entry->typeflag;
|
ret->name = BLI_strdup(entry->name);
|
||||||
|
ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath);
|
||||||
|
memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid));
|
||||||
|
ret->blentype = entry->blentype;
|
||||||
|
ret->typeflag = entry->typeflag;
|
||||||
|
|
||||||
|
BLI_addtail(&cache->cached_entries, ret);
|
||||||
|
}
|
||||||
|
|
||||||
BLI_addtail(&cache->cached_entries, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FileDirEntry *filelist_file_create_entries_block(FileList *filelist, const int index, const int size)
|
||||||
|
{
|
||||||
|
FileDirEntry *entry = NULL;
|
||||||
|
FileDirEntryArr tmp_arr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tmp_arr = filelist->filelist;
|
||||||
|
BLI_listbase_clear(&tmp_arr.entries);
|
||||||
|
|
||||||
|
if (filelist->ae) {
|
||||||
|
if (!filelist->ae->type->entries_block_get) {
|
||||||
|
printf("%s: Asset Engine %s does not implement 'entries_block_get'...\n", __func__, filelist->ae->type->name);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filelist->ae->type->entries_block_get(filelist->ae, index, index + size, &tmp_arr)) {
|
||||||
|
printf("%s: Failed to get [%d:%d] from AE %s\n", __func__, index, index + size, filelist->ae->type->name);
|
||||||
|
BKE_filedir_entryarr_clear(&tmp_arr);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, entry = tmp_arr.entries.first; i < size && entry; i++, entry = entry->next) {
|
||||||
|
BLI_assert(!BLI_listbase_is_empty(&entry->variants) && entry->nbr_variants);
|
||||||
|
BLI_assert(entry->act_variant < entry->nbr_variants);
|
||||||
|
if (!entry->name) {
|
||||||
|
char buff[FILE_MAX_LIBEXTRA];
|
||||||
|
entry->name = BLI_strdup(fileentry_uiname(filelist->filelist.root,
|
||||||
|
entry->relpath, entry->typeflag, buff));
|
||||||
|
}
|
||||||
|
if (!entry->entry) {
|
||||||
|
FileDirEntryVariant *variant = BLI_findlink(&entry->variants, entry->act_variant);
|
||||||
|
BLI_assert(!BLI_listbase_is_empty(&variant->revisions) && variant->nbr_revisions);
|
||||||
|
BLI_assert(variant->act_revision < variant->nbr_revisions);
|
||||||
|
entry->entry = BLI_findlink(&variant->revisions, variant->act_revision);
|
||||||
|
BLI_assert(entry->entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert(i == size && !entry);
|
||||||
|
|
||||||
|
entry = tmp_arr.entries.first;
|
||||||
|
/* Using filelist->filelist_cache.cached_entries as owner of that mem! */
|
||||||
|
BLI_movelisttolist(&filelist->filelist_cache.cached_entries, &tmp_arr.entries);
|
||||||
|
}
|
||||||
|
#if 0 /* UNUSED */
|
||||||
|
else {
|
||||||
|
entry = filelist_file_create_entry(filelist, index);
|
||||||
|
for (i = 1, idx = index + 1; i < size; i++, idx++) {
|
||||||
|
filelist_file_create_entry(filelist, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
|
static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
|
||||||
{
|
{
|
||||||
BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
|
BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
|
||||||
filelist_entry_free(entry);
|
BKE_filedir_entry_free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
|
static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
|
||||||
@@ -1489,22 +1649,24 @@ static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index
|
|||||||
|
|
||||||
/* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
|
/* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
|
||||||
ret = filelist_file_create_entry(filelist, index);
|
ret = filelist_file_create_entry(filelist, index);
|
||||||
old_index = cache->misc_entries_indices[cache->misc_cursor];
|
if (ret) {
|
||||||
if ((old = BLI_ghash_popkey(cache->misc_entries, SET_INT_IN_POINTER(old_index), NULL))) {
|
old_index = cache->misc_entries_indices[cache->misc_cursor];
|
||||||
BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL);
|
if ((old = BLI_ghash_popkey(cache->misc_entries, SET_INT_IN_POINTER(old_index), NULL))) {
|
||||||
filelist_file_release_entry(filelist, old);
|
BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL);
|
||||||
}
|
filelist_file_release_entry(filelist, old);
|
||||||
BLI_ghash_insert(cache->misc_entries, SET_INT_IN_POINTER(index), ret);
|
}
|
||||||
BLI_ghash_insert(cache->uuids, ret->uuid, ret);
|
BLI_ghash_insert(cache->misc_entries, SET_INT_IN_POINTER(index), ret);
|
||||||
|
BLI_ghash_insert(cache->uuids, ret->uuid, ret);
|
||||||
|
|
||||||
cache->misc_entries_indices[cache->misc_cursor] = index;
|
cache->misc_entries_indices[cache->misc_cursor] = index;
|
||||||
cache->misc_cursor = (cache->misc_cursor + 1) % cache_size;
|
cache->misc_cursor = (cache->misc_cursor + 1) % cache_size;
|
||||||
|
|
||||||
#if 0 /* Actually no, only block cached entries should have preview imho. */
|
#if 0 /* Actually no, only block cached entries should have preview imho. */
|
||||||
if (cache->previews_pool) {
|
if (cache->previews_pool) {
|
||||||
filelist_cache_previews_push(filelist, ret, index);
|
filelist_cache_previews_push(filelist, ret, index);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1548,7 +1710,30 @@ FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (filelist->ae) {
|
||||||
|
AssetEngine *engine = filelist->ae;
|
||||||
|
|
||||||
|
if (engine->type->entries_uuid_get) {
|
||||||
|
FileDirEntryArr r_entries;
|
||||||
|
AssetUUIDList uuids = {0};
|
||||||
|
AssetUUID asset_uuid = {0};
|
||||||
|
FileDirEntry *en = NULL;
|
||||||
|
|
||||||
|
uuids.uuids = &asset_uuid;
|
||||||
|
uuids.nbr_uuids = 1;
|
||||||
|
uuids.asset_engine_version = engine->type->version;
|
||||||
|
|
||||||
|
memcpy(asset_uuid.uuid_asset, uuid, sizeof(asset_uuid.uuid_asset));
|
||||||
|
/* Variants and revision uuids remain NULL here. */
|
||||||
|
|
||||||
|
if (engine->type->entries_uuid_get(engine, &uuids, &r_entries)) {
|
||||||
|
en = r_entries.entries.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
int fidx;
|
int fidx;
|
||||||
|
|
||||||
for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
|
for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
|
||||||
@@ -1582,7 +1767,20 @@ static bool filelist_file_cache_block_create(FileList *filelist, const int start
|
|||||||
{
|
{
|
||||||
FileListEntryCache *cache = &filelist->filelist_cache;
|
FileListEntryCache *cache = &filelist->filelist_cache;
|
||||||
|
|
||||||
{
|
if (filelist->ae) {
|
||||||
|
FileDirEntry *entry;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
entry = filelist_file_create_entries_block(filelist, start_index, size);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++, cursor++, entry = entry->next) {
|
||||||
|
// printf("%d, %p\n", i, entry);
|
||||||
|
cache->block_entries[cursor] = entry;
|
||||||
|
BLI_ghash_insert(cache->uuids, entry->uuid, entry);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
int i, idx;
|
int i, idx;
|
||||||
|
|
||||||
for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
|
for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
|
||||||
@@ -1604,19 +1802,17 @@ static bool filelist_file_cache_block_create(FileList *filelist, const int start
|
|||||||
static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor)
|
static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor)
|
||||||
{
|
{
|
||||||
FileListEntryCache *cache = &filelist->filelist_cache;
|
FileListEntryCache *cache = &filelist->filelist_cache;
|
||||||
|
int i;
|
||||||
|
|
||||||
{
|
for (i = 0; i < size; i++, cursor++) {
|
||||||
int i;
|
FileDirEntry *entry = cache->block_entries[cursor];
|
||||||
|
// printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
|
||||||
|
BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL);
|
||||||
|
filelist_file_release_entry(filelist, cache->block_entries[cursor]);
|
||||||
|
|
||||||
for (i = 0; i < size; i++, cursor++) {
|
|
||||||
FileDirEntry *entry = cache->block_entries[cursor];
|
|
||||||
// printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
|
|
||||||
BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL);
|
|
||||||
filelist_file_release_entry(filelist, entry);
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
cache->block_entries[cursor] = NULL;
|
cache->block_entries[cursor] = NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2113,6 +2309,60 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of selected entries, if use_ae is set also calls asset engine's load_pre callback.
|
||||||
|
* Note first item of returned list shall be used as 'active' file.
|
||||||
|
*/
|
||||||
|
FileDirEntryArr *filelist_selection_get(
|
||||||
|
FileList *filelist, FileCheckType check, const char *name, AssetUUIDList **r_uuids, const bool use_ae)
|
||||||
|
{
|
||||||
|
FileDirEntryArr *selection;
|
||||||
|
GHashIterator *iter = BLI_ghashIterator_new(filelist->selection_state);
|
||||||
|
bool done_name = false;
|
||||||
|
|
||||||
|
selection = MEM_callocN(sizeof(*selection), __func__);
|
||||||
|
strcpy(selection->root, filelist->filelist.root);
|
||||||
|
|
||||||
|
for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
|
||||||
|
const int *uuid = BLI_ghashIterator_getKey(iter);
|
||||||
|
FileDirEntry *entry_org = filelist_entry_find_uuid(filelist, uuid);
|
||||||
|
|
||||||
|
BLI_assert(BLI_ghashIterator_getValue(iter));
|
||||||
|
|
||||||
|
if (entry_org &&
|
||||||
|
(((ELEM(check, CHECK_ALL, CHECK_NONE))) ||
|
||||||
|
((check == CHECK_DIRS) && (entry_org->typeflag & FILE_TYPE_DIR)) ||
|
||||||
|
((check == CHECK_FILES) && !(entry_org->typeflag & FILE_TYPE_DIR)))) {
|
||||||
|
/* Always include 'name' (i.e. given relpath) */
|
||||||
|
if (!done_name && STREQ(entry_org->relpath, name)) {
|
||||||
|
FileDirEntry *entry_new = BKE_filedir_entry_copy(entry_org);
|
||||||
|
|
||||||
|
/* We add it in head - first entry in this list is always considered 'active' one. */
|
||||||
|
BLI_addhead(&selection->entries, entry_new);
|
||||||
|
selection->nbr_entries++;
|
||||||
|
done_name = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FileDirEntry *entry_new = BKE_filedir_entry_copy(entry_org);
|
||||||
|
BLI_addtail(&selection->entries, entry_new);
|
||||||
|
selection->nbr_entries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_ghashIterator_free(iter);
|
||||||
|
|
||||||
|
if (use_ae && filelist->ae) {
|
||||||
|
/* This will 'rewrite' selection list, returned paths are expected to be valid! */
|
||||||
|
*r_uuids = BKE_asset_engine_entries_load_pre(filelist->ae, selection);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*r_uuids = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
|
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
|
||||||
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
|
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
|
||||||
{
|
{
|
||||||
@@ -2226,7 +2476,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
|
|||||||
return nbr_entries;
|
return nbr_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memory for strings is passed into filelist[i].entry->relpath and freed in filelist_entry_free. */
|
/* memory for strings is passed into filelist[i].entry->relpath and freed in BKE_filedir_entry_free. */
|
||||||
if (group) {
|
if (group) {
|
||||||
idcode = groupname_to_code(group);
|
idcode = groupname_to_code(group);
|
||||||
names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames);
|
names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames);
|
||||||
@@ -2560,79 +2810,134 @@ typedef struct FileListReadJob {
|
|||||||
char main_name[FILE_MAX];
|
char main_name[FILE_MAX];
|
||||||
struct FileList *filelist;
|
struct FileList *filelist;
|
||||||
struct FileList *tmp_filelist; /* XXX We may use a simpler struct here... just a linked list and root path? */
|
struct FileList *tmp_filelist; /* XXX We may use a simpler struct here... just a linked list and root path? */
|
||||||
|
|
||||||
|
int ae_job_id;
|
||||||
|
float *progress;
|
||||||
|
short *stop;
|
||||||
} FileListReadJob;
|
} FileListReadJob;
|
||||||
|
|
||||||
static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
|
static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
|
||||||
{
|
{
|
||||||
FileListReadJob *flrj = flrjv;
|
FileListReadJob *flrj = flrjv;
|
||||||
|
|
||||||
// printf("START filelist reading (%d files, main thread: %d)\n",
|
if (flrj->filelist->ae) {
|
||||||
// flrj->filelist->filelist.nbr_entries, BLI_thread_is_main());
|
flrj->progress = progress;
|
||||||
|
flrj->stop = stop;
|
||||||
|
flrj->ae_job_id = AE_JOB_ID_UNSET;
|
||||||
|
/* When using AE engine, worker thread here is just sleeping! */
|
||||||
|
while ((flrj->filelist->flags & FL_IS_PENDING) && !*stop) {
|
||||||
|
PIL_sleep_ms(10);
|
||||||
|
*do_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_mutex_lock(&flrj->lock);
|
||||||
|
|
||||||
BLI_mutex_lock(&flrj->lock);
|
BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
|
||||||
|
|
||||||
BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
|
flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
|
||||||
|
|
||||||
flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
|
BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries);
|
||||||
|
flrj->tmp_filelist->filelist.nbr_entries = 0;
|
||||||
|
|
||||||
BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries);
|
flrj->tmp_filelist->filelist_intern.filtered = NULL;
|
||||||
flrj->tmp_filelist->filelist.nbr_entries = 0;
|
BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
|
||||||
|
memset(flrj->tmp_filelist->filelist_intern.curr_uuid, 0, sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid));
|
||||||
|
|
||||||
flrj->tmp_filelist->filelist_intern.filtered = NULL;
|
flrj->tmp_filelist->libfiledata = NULL;
|
||||||
BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
|
memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
|
||||||
memset(flrj->tmp_filelist->filelist_intern.curr_uuid, 0, sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid));
|
flrj->tmp_filelist->selection_state = NULL;
|
||||||
|
|
||||||
flrj->tmp_filelist->libfiledata = NULL;
|
BLI_mutex_unlock(&flrj->lock);
|
||||||
memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
|
|
||||||
flrj->tmp_filelist->selection_state = NULL;
|
|
||||||
|
|
||||||
BLI_mutex_unlock(&flrj->lock);
|
flrj->tmp_filelist->read_jobf(flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock);
|
||||||
|
}
|
||||||
flrj->tmp_filelist->read_jobf(flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelist_readjob_update(void *flrjv)
|
static void filelist_readjob_update(void *flrjv)
|
||||||
{
|
{
|
||||||
FileListReadJob *flrj = flrjv;
|
FileListReadJob *flrj = flrjv;
|
||||||
FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
|
|
||||||
ListBase new_entries = {NULL};
|
|
||||||
int nbr_entries, new_nbr_entries = 0;
|
|
||||||
|
|
||||||
BLI_movelisttolist(&new_entries, &fl_intern->entries);
|
if (flrj->filelist->flags & FL_FORCE_RESET) {
|
||||||
nbr_entries = flrj->filelist->filelist.nbr_entries;
|
*flrj->stop = true;
|
||||||
|
|
||||||
BLI_mutex_lock(&flrj->lock);
|
|
||||||
|
|
||||||
if (flrj->tmp_filelist->filelist.nbr_entries) {
|
|
||||||
/* We just move everything out of 'thread context' into final list. */
|
|
||||||
new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
|
|
||||||
BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
|
|
||||||
flrj->tmp_filelist->filelist.nbr_entries = 0;
|
|
||||||
}
|
}
|
||||||
|
else if (flrj->filelist->ae) {
|
||||||
|
/* We only communicate with asset engine from main thread! */
|
||||||
|
AssetEngine *ae = flrj->filelist->ae;
|
||||||
|
|
||||||
BLI_mutex_unlock(&flrj->lock);
|
if (flrj->ae_job_id == AE_JOB_ID_INVALID) {
|
||||||
|
BLI_assert(0); /* Should never reach this point... */
|
||||||
|
*flrj->progress = 1.0f;
|
||||||
|
*flrj->stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (new_nbr_entries) {
|
flrj->ae_job_id = ae->type->list_dir(ae, flrj->ae_job_id, &flrj->filelist->filelist);
|
||||||
/* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */
|
|
||||||
filelist_clear_ex(flrj->filelist, true, false);
|
|
||||||
|
|
||||||
flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING);
|
flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING);
|
||||||
}
|
|
||||||
|
|
||||||
/* if no new_nbr_entries, this is NOP */
|
if (flrj->ae_job_id == AE_JOB_ID_INVALID) { /* Immediate execution. */
|
||||||
BLI_movelisttolist(&fl_intern->entries, &new_entries);
|
*flrj->progress = 1.0f;
|
||||||
flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries;
|
*flrj->stop = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*flrj->progress = ae->type->progress(ae, flrj->ae_job_id);
|
||||||
|
if ((ae->type->status(ae, flrj->ae_job_id) & (AE_STATUS_RUNNING | AE_STATUS_VALID)) !=
|
||||||
|
(AE_STATUS_RUNNING | AE_STATUS_VALID))
|
||||||
|
{
|
||||||
|
*flrj->stop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
|
||||||
|
ListBase new_entries = {NULL};
|
||||||
|
int nbr_entries, new_nbr_entries = 0;
|
||||||
|
|
||||||
|
BLI_movelisttolist(&new_entries, &fl_intern->entries);
|
||||||
|
nbr_entries = flrj->filelist->filelist.nbr_entries;
|
||||||
|
|
||||||
|
BLI_mutex_lock(&flrj->lock);
|
||||||
|
|
||||||
|
if (flrj->tmp_filelist->filelist.nbr_entries) {
|
||||||
|
/* We just move everything out of 'thread context' into final list. */
|
||||||
|
new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
|
||||||
|
BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
|
||||||
|
flrj->tmp_filelist->filelist.nbr_entries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_mutex_unlock(&flrj->lock);
|
||||||
|
|
||||||
|
if (new_nbr_entries) {
|
||||||
|
/* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */
|
||||||
|
filelist_clear_ex(flrj->filelist, true, false);
|
||||||
|
|
||||||
|
flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no new_nbr_entries, this is NOP */
|
||||||
|
BLI_movelisttolist(&fl_intern->entries, &new_entries);
|
||||||
|
flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelist_readjob_endjob(void *flrjv)
|
static void filelist_readjob_endjob(void *flrjv)
|
||||||
{
|
{
|
||||||
FileListReadJob *flrj = flrjv;
|
FileListReadJob *flrj = flrjv;
|
||||||
|
|
||||||
/* In case there would be some dangling update... */
|
/* In case there would be some dangling update.
|
||||||
filelist_readjob_update(flrjv);
|
* Do not do this in case of ae job returning AE_JOB_ID_INVALID as job_id (immediate execution). */
|
||||||
|
if (flrj->filelist->ae == NULL || flrj->ae_job_id != AE_JOB_ID_INVALID) {
|
||||||
|
filelist_readjob_update(flrjv);
|
||||||
|
}
|
||||||
|
|
||||||
flrj->filelist->flags &= ~FL_IS_PENDING;
|
flrj->filelist->flags &= ~FL_IS_PENDING;
|
||||||
flrj->filelist->flags |= FL_IS_READY;
|
flrj->filelist->flags |= FL_IS_READY;
|
||||||
|
|
||||||
|
if (flrj->filelist->ae && !ELEM(flrj->ae_job_id, AE_JOB_ID_INVALID, AE_JOB_ID_UNSET)) {
|
||||||
|
AssetEngine *ae = flrj->filelist->ae;
|
||||||
|
ae->type->kill(ae, flrj->ae_job_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void filelist_readjob_free(void *flrjv)
|
static void filelist_readjob_free(void *flrjv)
|
||||||
|
@@ -37,12 +37,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
|
|
||||||
|
struct AssetEngineType;
|
||||||
|
struct AssetEngine;
|
||||||
struct BlendHandle;
|
struct BlendHandle;
|
||||||
struct FileList;
|
struct FileList;
|
||||||
struct FileSelection;
|
struct FileSelection;
|
||||||
struct wmWindowManager;
|
struct wmWindowManager;
|
||||||
|
|
||||||
struct FileDirEntry;
|
struct FileDirEntry;
|
||||||
|
struct FileDirEntryArr;
|
||||||
|
|
||||||
typedef enum FileSelType {
|
typedef enum FileSelType {
|
||||||
FILE_SEL_REMOVE = 0,
|
FILE_SEL_REMOVE = 0,
|
||||||
@@ -50,12 +55,6 @@ typedef enum FileSelType {
|
|||||||
FILE_SEL_TOGGLE = 2
|
FILE_SEL_TOGGLE = 2
|
||||||
} FileSelType;
|
} FileSelType;
|
||||||
|
|
||||||
typedef enum FileCheckType {
|
|
||||||
CHECK_DIRS = 1,
|
|
||||||
CHECK_FILES = 2,
|
|
||||||
CHECK_ALL = 3
|
|
||||||
} FileCheckType;
|
|
||||||
|
|
||||||
struct ListBase * folderlist_new(void);
|
struct ListBase * folderlist_new(void);
|
||||||
void folderlist_free(struct ListBase *folderlist);
|
void folderlist_free(struct ListBase *folderlist);
|
||||||
struct ListBase * folderlist_duplicate(ListBase *folderlist);
|
struct ListBase * folderlist_duplicate(ListBase *folderlist);
|
||||||
@@ -66,12 +65,10 @@ int folderlist_clear_next(struct SpaceFile *sfile);
|
|||||||
|
|
||||||
|
|
||||||
void filelist_setsorting(struct FileList *filelist, const short sort);
|
void filelist_setsorting(struct FileList *filelist, const short sort);
|
||||||
void filelist_sort(struct FileList *filelist);
|
|
||||||
|
|
||||||
void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
|
void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
|
||||||
const unsigned int filter, const unsigned int filter_id,
|
const unsigned int filter, const unsigned int filter_id,
|
||||||
const char *filter_glob, const char *filter_search);
|
const char *filter_glob, const char *filter_search);
|
||||||
void filelist_filter(struct FileList *filelist);
|
void filelist_sort_filter(struct FileList *filelist, struct FileSelectParams *params);
|
||||||
|
|
||||||
void filelist_init_icons(void);
|
void filelist_init_icons(void);
|
||||||
void filelist_free_icons(void);
|
void filelist_free_icons(void);
|
||||||
@@ -85,12 +82,14 @@ void filelist_clear(struct FileList *filelist);
|
|||||||
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection);
|
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection);
|
||||||
void filelist_free(struct FileList *filelist);
|
void filelist_free(struct FileList *filelist);
|
||||||
|
|
||||||
|
void filelist_assetengine_set(struct FileList *filelist, struct AssetEngineType *aet);
|
||||||
|
|
||||||
const char * filelist_dir(struct FileList *filelist);
|
const char * filelist_dir(struct FileList *filelist);
|
||||||
void filelist_setdir(struct FileList *filelist, char *r_dir);
|
void filelist_setdir(struct FileList *filelist, char *r_dir);
|
||||||
|
|
||||||
int filelist_files_ensure(struct FileList *filelist);
|
int filelist_files_ensure(struct FileList *filelist, struct FileSelectParams *params);
|
||||||
int filelist_empty(struct FileList *filelist);
|
int filelist_empty(struct FileList *filelist);
|
||||||
FileDirEntry * filelist_file(struct FileList *filelist, int index);
|
struct FileDirEntry *filelist_file(struct FileList *filelist, int index);
|
||||||
int filelist_file_findpath(struct FileList *filelist, const char *file);
|
int filelist_file_findpath(struct FileList *filelist, const char *file);
|
||||||
FileDirEntry * filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
|
FileDirEntry * filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
|
||||||
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
|
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
|
||||||
@@ -105,6 +104,8 @@ void filelist_entry_select_index_set(struct FileList *filelist, c
|
|||||||
void filelist_entries_select_index_range_set(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
|
void filelist_entries_select_index_range_set(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check);
|
||||||
unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check);
|
unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check);
|
||||||
unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check);
|
unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check);
|
||||||
|
struct FileDirEntryArr *filelist_selection_get(
|
||||||
|
struct FileList *filelist, FileCheckType check, const char *name, AssetUUIDList **r_uuids, const bool use_ae);
|
||||||
|
|
||||||
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
|
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
|
||||||
|
|
||||||
@@ -112,6 +113,8 @@ struct BlendHandle *filelist_lib(struct FileList *filelist);
|
|||||||
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group);
|
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group);
|
||||||
void filelist_freelib(struct FileList *filelist);
|
void filelist_freelib(struct FileList *filelist);
|
||||||
|
|
||||||
|
struct AssetEngine *filelist_assetengine_get(struct FileList *filelist);
|
||||||
|
|
||||||
void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
|
void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
|
||||||
void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa);
|
void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa);
|
||||||
int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa);
|
int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa);
|
||||||
|
@@ -501,7 +501,7 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
numfiles = filelist_files_ensure(sfile->files);
|
numfiles = filelist_files_ensure(sfile->files, params);
|
||||||
textheight = (int)file_font_pointsize();
|
textheight = (int)file_font_pointsize();
|
||||||
layout = sfile->layout;
|
layout = sfile->layout;
|
||||||
layout->textheight = textheight;
|
layout->textheight = textheight;
|
||||||
@@ -611,7 +611,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
FileDirEntry *file;
|
FileDirEntry *file;
|
||||||
int n = filelist_files_ensure(sfile->files);
|
int n = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
|
|
||||||
/* select any file that matches the pattern, this includes exact match
|
/* select any file that matches the pattern, this includes exact match
|
||||||
* if the user selects a single file by entering the filename
|
* if the user selects a single file by entering the filename
|
||||||
@@ -687,7 +687,7 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
|
|||||||
/* search if str matches the beginning of name */
|
/* search if str matches the beginning of name */
|
||||||
if (str[0] && sfile->files) {
|
if (str[0] && sfile->files) {
|
||||||
AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
|
AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
|
||||||
int nentries = filelist_files_ensure(sfile->files);
|
int nentries = filelist_files_ensure(sfile->files, ED_fileselect_get_params(sfile));
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nentries; ++i) {
|
for (i = 0; i < nentries; ++i) {
|
||||||
|
@@ -39,14 +39,15 @@
|
|||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_fileops_types.h"
|
#include "BLI_fileops_types.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
#include "BKE_appdir.h"
|
#include "BKE_appdir.h"
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_screen.h"
|
#include "BKE_screen.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
#include "WM_types.h"
|
#include "WM_types.h"
|
||||||
|
|
||||||
@@ -75,6 +76,8 @@ static SpaceLink *file_new(const bContext *UNUSED(C))
|
|||||||
sfile = MEM_callocN(sizeof(SpaceFile), "initfile");
|
sfile = MEM_callocN(sizeof(SpaceFile), "initfile");
|
||||||
sfile->spacetype = SPACE_FILE;
|
sfile->spacetype = SPACE_FILE;
|
||||||
|
|
||||||
|
BKE_asset_engines_get_default(sfile->asset_engine, sizeof(sfile->asset_engine));
|
||||||
|
|
||||||
/* header */
|
/* header */
|
||||||
ar = MEM_callocN(sizeof(ARegion), "header for file");
|
ar = MEM_callocN(sizeof(ARegion), "header for file");
|
||||||
BLI_addtail(&sfile->regionbase, ar);
|
BLI_addtail(&sfile->regionbase, ar);
|
||||||
@@ -165,6 +168,12 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
|
|||||||
*/
|
*/
|
||||||
fsmenu_refresh_bookmarks_status(ED_fsmenu_get());
|
fsmenu_refresh_bookmarks_status(ED_fsmenu_get());
|
||||||
|
|
||||||
|
if (!BKE_asset_engines_find(sfile->asset_engine)) {
|
||||||
|
BKE_asset_engines_get_default(sfile->asset_engine, sizeof(sfile->asset_engine));
|
||||||
|
ED_area_tag_refresh(sa);
|
||||||
|
ED_area_tag_redraw(sa);
|
||||||
|
}
|
||||||
|
|
||||||
if (sfile->layout) sfile->layout->dirty = true;
|
if (sfile->layout) sfile->layout->dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +193,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
|
|||||||
{
|
{
|
||||||
SpaceFile *sfileo = (SpaceFile *)sl;
|
SpaceFile *sfileo = (SpaceFile *)sl;
|
||||||
SpaceFile *sfilen = MEM_dupallocN(sl);
|
SpaceFile *sfilen = MEM_dupallocN(sl);
|
||||||
|
|
||||||
/* clear or remove stuff from old */
|
/* clear or remove stuff from old */
|
||||||
sfilen->op = NULL; /* file window doesn't own operators */
|
sfilen->op = NULL; /* file window doesn't own operators */
|
||||||
|
|
||||||
@@ -212,6 +221,12 @@ static void file_refresh(const bContext *C, ScrArea *sa)
|
|||||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||||
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
||||||
struct FSMenu *fsmenu = ED_fsmenu_get();
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
||||||
|
AssetEngineType *aet = NULL;
|
||||||
|
|
||||||
|
if (!STREQ(sfile->asset_engine, AE_FAKE_ENGINE_ID) && (params->type == FILE_LOADLIB)) {
|
||||||
|
/* Only allow asset engine usage in 'loadlib' (i.e. link/append) case. */
|
||||||
|
aet = BKE_asset_engines_find(sfile->asset_engine);
|
||||||
|
}
|
||||||
|
|
||||||
if (!sfile->folders_prev) {
|
if (!sfile->folders_prev) {
|
||||||
sfile->folders_prev = folderlist_new();
|
sfile->folders_prev = folderlist_new();
|
||||||
@@ -220,6 +235,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
|
|||||||
sfile->files = filelist_new(params->type);
|
sfile->files = filelist_new(params->type);
|
||||||
params->highlight_file = -1; /* added this so it opens nicer (ton) */
|
params->highlight_file = -1; /* added this so it opens nicer (ton) */
|
||||||
}
|
}
|
||||||
|
filelist_assetengine_set(sfile->files, aet);
|
||||||
filelist_setdir(sfile->files, params->dir);
|
filelist_setdir(sfile->files, params->dir);
|
||||||
filelist_setrecursion(sfile->files, params->recursion_level);
|
filelist_setrecursion(sfile->files, params->recursion_level);
|
||||||
filelist_setsorting(sfile->files, params->sort);
|
filelist_setsorting(sfile->files, params->sort);
|
||||||
@@ -247,8 +263,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filelist_sort(sfile->files);
|
filelist_sort_filter(sfile->files, params);
|
||||||
filelist_filter(sfile->files);
|
|
||||||
|
|
||||||
if (params->display == FILE_IMGDISPLAY) {
|
if (params->display == FILE_IMGDISPLAY) {
|
||||||
filelist_cache_previews_set(sfile->files, true);
|
filelist_cache_previews_set(sfile->files, true);
|
||||||
|
@@ -1568,7 +1568,7 @@ static void outliner_draw_tree_element(
|
|||||||
else
|
else
|
||||||
offsx += 2 * ufac;
|
offsx += 2 * ufac;
|
||||||
|
|
||||||
if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
|
if (tselem->type == 0 && ID_IS_LINKED(tselem->id)) {
|
||||||
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
|
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
|
||||||
if (tselem->id->tag & LIB_TAG_MISSING) {
|
if (tselem->id->tag & LIB_TAG_MISSING) {
|
||||||
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
|
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
|
||||||
@@ -1579,6 +1579,22 @@ static void outliner_draw_tree_element(
|
|||||||
else {
|
else {
|
||||||
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
|
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
|
||||||
}
|
}
|
||||||
|
if (tselem->id->uuid) {
|
||||||
|
offsx += UI_UNIT_X;
|
||||||
|
UI_icon_draw((float)startx + offsx - 0.5f * ufac, (float)*starty + 1.5f * ufac, ICON_SOLO_ON);
|
||||||
|
if (tselem->id->uuid->tag & UUID_TAG_ENGINE_MISSING) {
|
||||||
|
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_GHOST_ENABLED);
|
||||||
|
}
|
||||||
|
else if (tselem->id->uuid->tag & UUID_TAG_ASSET_MISSING) {
|
||||||
|
/* Nothing special (underlying icon is already 'broken' one)... */
|
||||||
|
}
|
||||||
|
else if (tselem->id->uuid->tag & UUID_TAG_ASSET_RELOAD) {
|
||||||
|
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_FILE_REFRESH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Nothing special (underlying icon is already 'OK' one)... */
|
||||||
|
}
|
||||||
|
}
|
||||||
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
|
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
|
||||||
offsx += UI_UNIT_X;
|
offsx += UI_UNIT_X;
|
||||||
}
|
}
|
||||||
|
@@ -435,10 +435,11 @@ static void id_local_cb(
|
|||||||
bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
|
bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
|
||||||
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
|
||||||
{
|
{
|
||||||
if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
|
if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
|
||||||
Main *bmain = CTX_data_main(C);
|
Main *bmain = CTX_data_main(C);
|
||||||
/* if the ID type has no special local function,
|
/* if the ID type has no special local function,
|
||||||
* just clear the lib */
|
* just clear the lib. */
|
||||||
|
/* XXX This is very, very, **very** suspicious - should not be handled that way at all!!! */
|
||||||
if (id_make_local(bmain, tselem->id, false, false) == false) {
|
if (id_make_local(bmain, tselem->id, false, false) == false) {
|
||||||
id_clear_lib_data(bmain, tselem->id);
|
id_clear_lib_data(bmain, tselem->id);
|
||||||
}
|
}
|
||||||
|
@@ -165,3 +165,23 @@ void SCRIPT_OT_autoexec_warn_clear(wmOperatorType *ot)
|
|||||||
/* api callbacks */
|
/* api callbacks */
|
||||||
ot->exec = script_autoexec_warn_clear_exec;
|
ot->exec = script_autoexec_warn_clear_exec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int script_assets_warn_clear_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
G.f |= G_ASSETS_QUIET;
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCRIPT_OT_assets_warn_clear(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Silence Assets Warnings";
|
||||||
|
ot->description = "Ignore assets warning and errors";
|
||||||
|
ot->idname = "SCRIPT_OT_assets_warn_clear";
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_INTERNAL;
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->exec = script_assets_warn_clear_exec;
|
||||||
|
}
|
||||||
|
@@ -41,6 +41,7 @@ void script_keymap(struct wmKeyConfig *keyconf);
|
|||||||
void SCRIPT_OT_reload(struct wmOperatorType *ot);
|
void SCRIPT_OT_reload(struct wmOperatorType *ot);
|
||||||
void SCRIPT_OT_python_file_run(struct wmOperatorType *ot);
|
void SCRIPT_OT_python_file_run(struct wmOperatorType *ot);
|
||||||
void SCRIPT_OT_autoexec_warn_clear(struct wmOperatorType *ot);
|
void SCRIPT_OT_autoexec_warn_clear(struct wmOperatorType *ot);
|
||||||
|
void SCRIPT_OT_assets_warn_clear(struct wmOperatorType *ot);
|
||||||
|
|
||||||
#endif /* __SCRIPT_INTERN_H__ */
|
#endif /* __SCRIPT_INTERN_H__ */
|
||||||
|
|
||||||
|
@@ -45,6 +45,7 @@ void script_operatortypes(void)
|
|||||||
WM_operatortype_append(SCRIPT_OT_python_file_run);
|
WM_operatortype_append(SCRIPT_OT_python_file_run);
|
||||||
WM_operatortype_append(SCRIPT_OT_reload);
|
WM_operatortype_append(SCRIPT_OT_reload);
|
||||||
WM_operatortype_append(SCRIPT_OT_autoexec_warn_clear);
|
WM_operatortype_append(SCRIPT_OT_autoexec_warn_clear);
|
||||||
|
WM_operatortype_append(SCRIPT_OT_assets_warn_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_keymap(wmKeyConfig *UNUSED(keyconf))
|
void script_keymap(wmKeyConfig *UNUSED(keyconf))
|
||||||
|
@@ -106,6 +106,46 @@ enum {
|
|||||||
|
|
||||||
/* add any future new id property types here.*/
|
/* add any future new id property types here.*/
|
||||||
|
|
||||||
|
/* About Unique identifier.
|
||||||
|
* Each engine is free to use it as it likes - it will be the only thing passed to it by blender to identify
|
||||||
|
* asset/variant/version (concatenating the three into a single 48 bytes one).
|
||||||
|
* Assumed to be 128bits, handled as four integers due to lack of real bytes proptype in RNA :|.
|
||||||
|
*/
|
||||||
|
#define ASSET_UUID_LENGTH 16
|
||||||
|
|
||||||
|
/* Used to communicate with asset engines outside of 'import' context. */
|
||||||
|
typedef struct AssetUUID {
|
||||||
|
int uuid_asset[4];
|
||||||
|
int uuid_variant[4];
|
||||||
|
int uuid_revision[4];
|
||||||
|
short flag; /* Saved. */
|
||||||
|
short tag; /* Runtime. */
|
||||||
|
int pad_i1;
|
||||||
|
} AssetUUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uuid->flag (persitent, saved in .blend files).
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
UUID_FLAG_LAST_REVISION = 1 << 0, /* This asset should always use latest available revision. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uuid->tag (runtime only).
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
UUID_TAG_ENGINE_MISSING = 1 << 0, /* The asset engine used for this asset is not known by Blender. */
|
||||||
|
UUID_TAG_ASSET_MISSING = 1 << 1, /* The asset engine was found but does not know about this asset (anymore). */
|
||||||
|
|
||||||
|
UUID_TAG_ASSET_RELOAD = 1 << 8, /* Set by the asset engine to indicates that that asset has to be reloaded. */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct AssetUUIDList {
|
||||||
|
AssetUUID *uuids;
|
||||||
|
int nbr_uuids;
|
||||||
|
int asset_engine_version;
|
||||||
|
} AssetUUIDList;
|
||||||
|
|
||||||
/* watch it: Sequence has identical beginning. */
|
/* watch it: Sequence has identical beginning. */
|
||||||
/**
|
/**
|
||||||
* ID is the first thing included in all serializable types. It
|
* ID is the first thing included in all serializable types. It
|
||||||
@@ -134,8 +174,42 @@ typedef struct ID {
|
|||||||
int us;
|
int us;
|
||||||
int icon_id;
|
int icon_id;
|
||||||
IDProperty *properties;
|
IDProperty *properties;
|
||||||
|
|
||||||
|
AssetUUID *uuid;
|
||||||
} ID;
|
} ID;
|
||||||
|
|
||||||
|
/* Note: Those two structs are for now being runtime-stored in Library datablocks.
|
||||||
|
* Later it may be interesting to also cache those globally in some ghash...
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* An asset reference, storing the uuid and a list of pointers to all used IDs.
|
||||||
|
* Runtime only currently.
|
||||||
|
*/
|
||||||
|
#
|
||||||
|
#
|
||||||
|
typedef struct AssetRef {
|
||||||
|
struct AssetRef *next, *prev;
|
||||||
|
AssetUUID uuid;
|
||||||
|
|
||||||
|
/* Runtime */
|
||||||
|
ListBase id_list; /* List of pointers to all IDs used by this asset (first one being 'root' one). */
|
||||||
|
} AssetRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An asset repository reference, storing all that's needed to find the repo, and a list of loaded assets.
|
||||||
|
* WARNING: this is per library, **not** per asset repo.
|
||||||
|
*/
|
||||||
|
typedef struct AssetRepositoryRef {
|
||||||
|
char asset_engine[64]; /* MAX_ST_NAME */
|
||||||
|
int asset_engine_version;
|
||||||
|
int pad_i1;
|
||||||
|
/* 'Path' to asset engine's root of the reprository, can be an url, whatever... */
|
||||||
|
char root[768]; /* FILE_MAXDIR */
|
||||||
|
|
||||||
|
/* Runtime */
|
||||||
|
ListBase assets; /* A list of AssetRef assets from this lib. */
|
||||||
|
} AssetRepositoryRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For each library file used, a Library struct is added to Main
|
* For each library file used, a Library struct is added to Main
|
||||||
* WARNING: readfile.c, expand_doit() reads this struct without DNA check!
|
* WARNING: readfile.c, expand_doit() reads this struct without DNA check!
|
||||||
@@ -143,7 +217,8 @@ typedef struct ID {
|
|||||||
typedef struct Library {
|
typedef struct Library {
|
||||||
ID id;
|
ID id;
|
||||||
struct FileData *filedata;
|
struct FileData *filedata;
|
||||||
char name[1024]; /* path name used for reading, can be relative and edited in the outliner */
|
/* path name used for reading, can be relative and edited in the outliner. */
|
||||||
|
char name[1024];
|
||||||
|
|
||||||
/* absolute filepath, this is only for convenience, 'name' is the real path used on file read but in
|
/* absolute filepath, this is only for convenience, 'name' is the real path used on file read but in
|
||||||
* some cases its useful to access the absolute one.
|
* some cases its useful to access the absolute one.
|
||||||
@@ -155,10 +230,20 @@ typedef struct Library {
|
|||||||
|
|
||||||
struct PackedFile *packedfile;
|
struct PackedFile *packedfile;
|
||||||
|
|
||||||
|
AssetRepositoryRef *asset_repository;
|
||||||
|
|
||||||
int temp_index;
|
int temp_index;
|
||||||
int _pad;
|
|
||||||
|
short flag;
|
||||||
|
short pad_s1;
|
||||||
} Library;
|
} Library;
|
||||||
|
|
||||||
|
/* Library.flag */
|
||||||
|
enum {
|
||||||
|
/* The library does not actually exist, used to allow handling of files from asset engines. */
|
||||||
|
LIBRARY_FLAG_VIRTUAL = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
enum eIconSizes {
|
enum eIconSizes {
|
||||||
ICON_SIZE_ICON = 0,
|
ICON_SIZE_ICON = 0,
|
||||||
ICON_SIZE_PREVIEW = 1,
|
ICON_SIZE_PREVIEW = 1,
|
||||||
@@ -269,7 +354,10 @@ typedef struct PreviewImage {
|
|||||||
|
|
||||||
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
|
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
|
||||||
|
|
||||||
#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL)
|
#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
|
||||||
|
#define LIB_IS_VIRTUAL(_lib) (((_lib)->flag & LIBRARY_FLAG_VIRTUAL) != 0)
|
||||||
|
#define ID_IS_LINKED_DATABLOCK(_id) (ID_IS_LINKED(_id) && !LIB_IS_VIRTUAL(((ID *)(_id))->lib))
|
||||||
|
#define ID_IS_LINKED_DATAPATH(_id) (ID_IS_LINKED(_id) && LIB_IS_VIRTUAL(((ID *)(_id))->lib))
|
||||||
|
|
||||||
#ifdef GS
|
#ifdef GS
|
||||||
# undef GS
|
# undef GS
|
||||||
@@ -280,8 +368,12 @@ typedef struct PreviewImage {
|
|||||||
#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
|
#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
|
||||||
#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
|
#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
|
||||||
|
|
||||||
|
#define ID_VIRTUAL_LIBRARY_VALID(_id) (ELEM(GS((_id)->name), ID_IM, ID_VF, ID_TXT, ID_SO))
|
||||||
|
|
||||||
/* id->flag (persitent). */
|
/* id->flag (persitent). */
|
||||||
enum {
|
enum {
|
||||||
|
/* Flag asset IDs (the ones who should have a valid uuid). */
|
||||||
|
LIB_ASSET = 1 << 0,
|
||||||
LIB_FAKEUSER = 1 << 9,
|
LIB_FAKEUSER = 1 << 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -304,6 +396,8 @@ enum {
|
|||||||
LIB_TAG_EXTERN = 1 << 0,
|
LIB_TAG_EXTERN = 1 << 0,
|
||||||
/* RESET_NEVER Datablock is from a library, and is only used (linked) inderectly through other libraries. */
|
/* RESET_NEVER Datablock is from a library, and is only used (linked) inderectly through other libraries. */
|
||||||
LIB_TAG_INDIRECT = 1 << 1,
|
LIB_TAG_INDIRECT = 1 << 1,
|
||||||
|
/* RESET_NEVER Datablock is (or is used by) an asset. */
|
||||||
|
LIB_TAG_ASSET = 1 << 9,
|
||||||
|
|
||||||
/* RESET_AFTER_USE Three flags used internally in readfile.c, to mark IDs needing to be read (only done once). */
|
/* RESET_AFTER_USE Three flags used internally in readfile.c, to mark IDs needing to be read (only done once). */
|
||||||
LIB_TAG_NEED_EXPAND = 1 << 3,
|
LIB_TAG_NEED_EXPAND = 1 << 3,
|
||||||
|
@@ -280,6 +280,7 @@ typedef struct Object {
|
|||||||
struct CurveCache *curve_cache;
|
struct CurveCache *curve_cache;
|
||||||
|
|
||||||
struct DerivedMesh *derivedDeform, *derivedFinal;
|
struct DerivedMesh *derivedDeform, *derivedFinal;
|
||||||
|
void *pad_v1;
|
||||||
uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
|
uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
|
||||||
uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */
|
uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */
|
||||||
unsigned int state; /* bit masks of game controllers that are active */
|
unsigned int state; /* bit masks of game controllers that are active */
|
||||||
|
@@ -1591,6 +1591,8 @@ typedef struct Scene {
|
|||||||
/* Movie Tracking */
|
/* Movie Tracking */
|
||||||
struct MovieClip *clip; /* active movie clip */
|
struct MovieClip *clip; /* active movie clip */
|
||||||
|
|
||||||
|
void *pad_v1;
|
||||||
|
|
||||||
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
|
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
|
||||||
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
|
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
|
||||||
|
|
||||||
|
@@ -629,6 +629,8 @@ typedef struct SpaceFile {
|
|||||||
|
|
||||||
int scroll_offset;
|
int scroll_offset;
|
||||||
|
|
||||||
|
char asset_engine[64]; /* BKE_ST_MAXNAME */
|
||||||
|
|
||||||
struct FileSelectParams *params; /* config and input for file select */
|
struct FileSelectParams *params; /* config and input for file select */
|
||||||
|
|
||||||
struct FileList *files; /* holds the list of files to show */
|
struct FileList *files; /* holds the list of files to show */
|
||||||
@@ -755,26 +757,6 @@ typedef enum eDirEntry_SelectFlag {
|
|||||||
|
|
||||||
/* ***** Related to file browser, but never saved in DNA, only here to help with RNA. ***** */
|
/* ***** Related to file browser, but never saved in DNA, only here to help with RNA. ***** */
|
||||||
|
|
||||||
/* About Unique identifier.
|
|
||||||
* Stored in a CustomProps once imported.
|
|
||||||
* Each engine is free to use it as it likes - it will be the only thing passed to it by blender to identify
|
|
||||||
* asset/variant/version (concatenating the three into a single 48 bytes one).
|
|
||||||
* Assumed to be 128bits, handled as four integers due to lack of real bytes proptype in RNA :|.
|
|
||||||
*/
|
|
||||||
#define ASSET_UUID_LENGTH 16
|
|
||||||
|
|
||||||
/* Used to communicate with asset engines outside of 'import' context. */
|
|
||||||
typedef struct AssetUUID {
|
|
||||||
int uuid_asset[4];
|
|
||||||
int uuid_variant[4];
|
|
||||||
int uuid_revision[4];
|
|
||||||
} AssetUUID;
|
|
||||||
|
|
||||||
typedef struct AssetUUIDList {
|
|
||||||
AssetUUID *uuids;
|
|
||||||
int nbr_uuids, pad;
|
|
||||||
} AssetUUIDList;
|
|
||||||
|
|
||||||
/* Container for a revision, only relevant in asset context. */
|
/* Container for a revision, only relevant in asset context. */
|
||||||
typedef struct FileDirEntryRevision {
|
typedef struct FileDirEntryRevision {
|
||||||
struct FileDirEntryRevision *next, *prev;
|
struct FileDirEntryRevision *next, *prev;
|
||||||
@@ -848,7 +830,6 @@ typedef struct FileDirEntryArr {
|
|||||||
ListBase entries;
|
ListBase entries;
|
||||||
int nbr_entries;
|
int nbr_entries;
|
||||||
int nbr_entries_filtered;
|
int nbr_entries_filtered;
|
||||||
int entry_idx_start, entry_idx_end;
|
|
||||||
|
|
||||||
char root[1024]; /* FILE_MAX */
|
char root[1024]; /* FILE_MAX */
|
||||||
} FileDirEntryArr;
|
} FileDirEntryArr;
|
||||||
|
@@ -62,6 +62,7 @@ typedef struct Text {
|
|||||||
int undo_pos, undo_len;
|
int undo_pos, undo_len;
|
||||||
|
|
||||||
void *compiled;
|
void *compiled;
|
||||||
|
void *pad_v1;
|
||||||
double mtime;
|
double mtime;
|
||||||
} Text;
|
} Text;
|
||||||
|
|
||||||
|
@@ -71,6 +71,12 @@ extern StructRNA RNA_Armature;
|
|||||||
extern StructRNA RNA_ArmatureModifier;
|
extern StructRNA RNA_ArmatureModifier;
|
||||||
extern StructRNA RNA_ArmatureSensor;
|
extern StructRNA RNA_ArmatureSensor;
|
||||||
extern StructRNA RNA_ArrayModifier;
|
extern StructRNA RNA_ArrayModifier;
|
||||||
|
extern StructRNA RNA_AssetEngine;
|
||||||
|
extern StructRNA RNA_AssetEntry;
|
||||||
|
extern StructRNA RNA_AssetList;
|
||||||
|
extern StructRNA RNA_AssetRevision;
|
||||||
|
extern StructRNA RNA_AssetUUID;
|
||||||
|
extern StructRNA RNA_AssetVariant;
|
||||||
extern StructRNA RNA_BackgroundImage;
|
extern StructRNA RNA_BackgroundImage;
|
||||||
extern StructRNA RNA_BevelModifier;
|
extern StructRNA RNA_BevelModifier;
|
||||||
extern StructRNA RNA_SplinePoint;
|
extern StructRNA RNA_SplinePoint;
|
||||||
|
@@ -36,6 +36,7 @@ set(DEFSRC
|
|||||||
rna_animation.c
|
rna_animation.c
|
||||||
rna_animviz.c
|
rna_animviz.c
|
||||||
rna_armature.c
|
rna_armature.c
|
||||||
|
rna_asset.c
|
||||||
rna_boid.c
|
rna_boid.c
|
||||||
rna_brush.c
|
rna_brush.c
|
||||||
rna_camera.c
|
rna_camera.c
|
||||||
|
@@ -3299,6 +3299,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
|
|||||||
{"rna_animviz.c", NULL, RNA_def_animviz},
|
{"rna_animviz.c", NULL, RNA_def_animviz},
|
||||||
{"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator},
|
{"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator},
|
||||||
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
|
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
|
||||||
|
{"rna_asset.c", NULL, RNA_def_asset},
|
||||||
{"rna_boid.c", NULL, RNA_def_boid},
|
{"rna_boid.c", NULL, RNA_def_boid},
|
||||||
{"rna_brush.c", NULL, RNA_def_brush},
|
{"rna_brush.c", NULL, RNA_def_brush},
|
||||||
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
|
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
|
||||||
|
@@ -716,6 +716,29 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
|
|||||||
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
|
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_ID_asset_dependencies_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
ID *id = ptr->data;
|
||||||
|
|
||||||
|
if (id->uuid && id->lib) {
|
||||||
|
AssetRef *aref = BKE_library_asset_repository_asset_find(id->lib, id);
|
||||||
|
if (aref) {
|
||||||
|
rna_iterator_listbase_begin(iter, &aref->id_list, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rna_iterator_listbase_begin(iter, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PointerRNA rna_ID_asset_dependencies_get(CollectionPropertyIterator *iter)
|
||||||
|
{
|
||||||
|
ListBaseIterator *internal = &iter->internal.listbase;
|
||||||
|
PointerRNA ptr;
|
||||||
|
|
||||||
|
RNA_id_pointer_create((ID *)((LinkData *)internal->link)->data, &ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static void rna_def_ID_properties(BlenderRNA *brna)
|
static void rna_def_ID_properties(BlenderRNA *brna)
|
||||||
@@ -978,6 +1001,20 @@ static void rna_def_ID(BlenderRNA *brna)
|
|||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL);
|
RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* XXX Not sure we actually want those two in our RNA in the end.
|
||||||
|
* But at least for now, they are important debug tools! */
|
||||||
|
prop = RNA_def_pointer(srna, "asset_uuid", "AssetUUID", "Asset UUID",
|
||||||
|
"Unique identifier of the asset represented by that ID (NULL if not an asset)");
|
||||||
|
RNA_def_property_pointer_sdna(prop, NULL, "uuid");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
|
prop = RNA_def_collection(srna, "asset_dependencies", "ID", "Asset Dependencies",
|
||||||
|
"A list of all IDs used by this asset");
|
||||||
|
RNA_def_property_collection_funcs(prop, "rna_ID_asset_dependencies_begin", "rna_iterator_listbase_next",
|
||||||
|
"rna_iterator_listbase_end", "rna_ID_asset_dependencies_get",
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
/* functions */
|
/* functions */
|
||||||
func = RNA_def_function(srna, "copy", "rna_ID_copy");
|
func = RNA_def_function(srna, "copy", "rna_ID_copy");
|
||||||
RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)");
|
RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)");
|
||||||
|
1292
source/blender/makesrna/intern/rna_asset.c
Normal file
1292
source/blender/makesrna/intern/rna_asset.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -130,6 +130,7 @@ void RNA_def_action(struct BlenderRNA *brna);
|
|||||||
void RNA_def_animation(struct BlenderRNA *brna);
|
void RNA_def_animation(struct BlenderRNA *brna);
|
||||||
void RNA_def_animviz(struct BlenderRNA *brna);
|
void RNA_def_animviz(struct BlenderRNA *brna);
|
||||||
void RNA_def_armature(struct BlenderRNA *brna);
|
void RNA_def_armature(struct BlenderRNA *brna);
|
||||||
|
void RNA_def_asset(struct BlenderRNA *brna);
|
||||||
void RNA_def_actuator(struct BlenderRNA *brna);
|
void RNA_def_actuator(struct BlenderRNA *brna);
|
||||||
void RNA_def_boid(struct BlenderRNA *brna);
|
void RNA_def_boid(struct BlenderRNA *brna);
|
||||||
void RNA_def_brush(struct BlenderRNA *brna);
|
void RNA_def_brush(struct BlenderRNA *brna);
|
||||||
|
@@ -31,6 +31,11 @@
|
|||||||
|
|
||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_define.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
#include "BKE_key.h"
|
#include "BKE_key.h"
|
||||||
#include "BKE_movieclip.h"
|
#include "BKE_movieclip.h"
|
||||||
@@ -46,9 +51,6 @@
|
|||||||
#include "DNA_mask_types.h"
|
#include "DNA_mask_types.h"
|
||||||
#include "DNA_view3d_types.h"
|
#include "DNA_view3d_types.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
#include "RNA_define.h"
|
|
||||||
|
|
||||||
#include "rna_internal.h"
|
#include "rna_internal.h"
|
||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
@@ -247,9 +249,11 @@ EnumPropertyItem rna_enum_file_sort_items[] = {
|
|||||||
#include "DNA_screen_types.h"
|
#include "DNA_screen_types.h"
|
||||||
#include "DNA_userdef_types.h"
|
#include "DNA_userdef_types.h"
|
||||||
|
|
||||||
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
|
|
||||||
#include "BKE_animsys.h"
|
#include "BKE_animsys.h"
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_brush.h"
|
#include "BKE_brush.h"
|
||||||
#include "BKE_colortools.h"
|
#include "BKE_colortools.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
@@ -1603,6 +1607,47 @@ static EnumPropertyItem *rna_FileSelectParams_recursion_level_itemf(
|
|||||||
return fileselectparams_recursion_level_items;
|
return fileselectparams_recursion_level_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rna_FileBrowser_AE_type_enum_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
SpaceFile *sf = ptr->data;
|
||||||
|
return BLI_findstringindex(&asset_engines, sf->asset_engine, offsetof(AssetEngineType, idname));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_FileBrowser_AE_type_enum_set(PointerRNA *ptr, const int value)
|
||||||
|
{
|
||||||
|
SpaceFile *sf = ptr->data;
|
||||||
|
AssetEngineType *aet = BLI_findlink(&asset_engines, value);
|
||||||
|
|
||||||
|
if (aet) {
|
||||||
|
BLI_strncpy(sf->asset_engine, aet->idname, sizeof(sf->asset_engine));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static EnumPropertyItem *rna_FileBrowser_AE_type_enum_itemf(
|
||||||
|
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
|
||||||
|
{
|
||||||
|
EnumPropertyItem *items = NULL;
|
||||||
|
AssetEngineType *aet = NULL;
|
||||||
|
int totitem = 0;
|
||||||
|
|
||||||
|
for (aet = asset_engines.first; aet; aet = aet->next) {
|
||||||
|
EnumPropertyItem item = {totitem, aet->idname, 0, aet->name, ""};
|
||||||
|
RNA_enum_item_add(&items, &totitem, &item);
|
||||||
|
}
|
||||||
|
|
||||||
|
RNA_enum_item_end(&items, &totitem);
|
||||||
|
*r_free = true;
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PointerRNA rna_FileBrowser_AE_ptr_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
SpaceFile *sfile = ptr->data;
|
||||||
|
AssetEngine *ae = ED_filelist_assetengine_get(sfile);
|
||||||
|
return rna_pointer_inherit_refine(ptr, &RNA_AssetEngine, ae);
|
||||||
|
}
|
||||||
|
|
||||||
static void rna_FileBrowser_FSMenuEntry_path_get(PointerRNA *ptr, char *value)
|
static void rna_FileBrowser_FSMenuEntry_path_get(PointerRNA *ptr, char *value)
|
||||||
{
|
{
|
||||||
char *path = ED_fsmenu_entry_get_path(ptr->data);
|
char *path = ED_fsmenu_entry_get_path(ptr->data);
|
||||||
@@ -4034,10 +4079,29 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
|
|||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
static EnumPropertyItem asset_engine_items[] = {
|
||||||
|
{0, AE_FAKE_ENGINE_ID, 0, "None", ""},
|
||||||
|
{0, NULL, 0, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
srna = RNA_def_struct(brna, "SpaceFileBrowser", "Space");
|
srna = RNA_def_struct(brna, "SpaceFileBrowser", "Space");
|
||||||
RNA_def_struct_sdna(srna, "SpaceFile");
|
RNA_def_struct_sdna(srna, "SpaceFile");
|
||||||
RNA_def_struct_ui_text(srna, "Space File Browser", "File browser space data");
|
RNA_def_struct_ui_text(srna, "Space File Browser", "File browser space data");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "asset_engine_type", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_ui_text(prop, "Asset Engine Type", "Active asset engine type");
|
||||||
|
RNA_def_property_enum_items(prop, asset_engine_items);
|
||||||
|
RNA_def_property_enum_funcs(prop, "rna_FileBrowser_AE_type_enum_get", "rna_FileBrowser_AE_type_enum_set",
|
||||||
|
"rna_FileBrowser_AE_type_enum_itemf");
|
||||||
|
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "asset_engine", PROP_POINTER, PROP_NONE);
|
||||||
|
RNA_def_property_ui_text(prop, "Asset Engine", "Active asset engine");
|
||||||
|
RNA_def_property_struct_type(prop, "AssetEngine");
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
RNA_def_property_pointer_funcs(prop, "rna_FileBrowser_AE_ptr_get", NULL, NULL, NULL);
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE);
|
prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE);
|
||||||
RNA_def_property_pointer_sdna(prop, NULL, "params");
|
RNA_def_property_pointer_sdna(prop, NULL, "params");
|
||||||
RNA_def_property_ui_text(prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser");
|
RNA_def_property_ui_text(prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser");
|
||||||
|
@@ -1648,6 +1648,16 @@ static void rna_def_operator_filelist_element(BlenderRNA *brna)
|
|||||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_FILENAME);
|
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_FILENAME);
|
||||||
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
RNA_def_property_ui_text(prop, "Name", "Name of a file or directory within a file list");
|
RNA_def_property_ui_text(prop, "Name", "Name of a file or directory within a file list");
|
||||||
|
|
||||||
|
prop = RNA_def_int_vector(srna, "asset_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Asset UUID", "Identifier of this item in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
|
prop = RNA_def_int_vector(srna, "variant_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Variant UUID", "Identifier of this item's variant in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
|
prop = RNA_def_int_vector(srna, "revision_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Revision UUID", "Identifier of this item's revision in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_def_event(BlenderRNA *brna)
|
static void rna_def_event(BlenderRNA *brna)
|
||||||
|
@@ -350,7 +350,14 @@ static PyGetSetDef bpy_app_getsets[] = {
|
|||||||
{(char *)"autoexec_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL},
|
{(char *)"autoexec_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL},
|
||||||
{(char *)"autoexec_fail_quiet", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL_QUIET},
|
{(char *)"autoexec_fail_quiet", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL_QUIET},
|
||||||
{(char *)"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
|
{(char *)"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
|
||||||
{NULL, NULL, NULL, NULL, NULL}
|
|
||||||
|
/* Assets */
|
||||||
|
{(char *)"assets_need_reload", bpy_app_global_flag_get, NULL, NULL, (void *)G_ASSETS_NEED_RELOAD},
|
||||||
|
{(char *)"assets_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_ASSETS_FAIL},
|
||||||
|
{(char *)"assets_quiet", bpy_app_global_flag_get, NULL, NULL, (void *)G_ASSETS_QUIET},
|
||||||
|
// {(char *)"assets_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
|
||||||
|
|
||||||
|
{NULL, NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void py_struct_seq_getset_init(void)
|
static void py_struct_seq_getset_init(void)
|
||||||
|
@@ -7832,7 +7832,7 @@ PyDoc_STRVAR(pyrna_register_class_doc,
|
|||||||
" Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n"
|
" Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n"
|
||||||
" :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
|
" :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
|
||||||
" :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
|
" :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
|
||||||
" :class:`bpy.types.RenderEngine`).\n"
|
" :class:`bpy.types.RenderEngine`, :class:`bpy.types.AssetEngine`).\n"
|
||||||
"\n"
|
"\n"
|
||||||
" If the class has a *register* class method it will be called\n"
|
" If the class has a *register* class method it will be called\n"
|
||||||
" before registration.\n"
|
" before registration.\n"
|
||||||
|
@@ -443,6 +443,7 @@ enum {
|
|||||||
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
|
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
|
||||||
WM_JOB_TYPE_POINTCACHE,
|
WM_JOB_TYPE_POINTCACHE,
|
||||||
WM_JOB_TYPE_DPAINT_BAKE,
|
WM_JOB_TYPE_DPAINT_BAKE,
|
||||||
|
WM_JOB_TYPE_ASSET_UPDATECHECK,
|
||||||
/* add as needed, screencast, seq proxy build
|
/* add as needed, screencast, seq proxy build
|
||||||
* if having hard coded values is a problem */
|
* if having hard coded values is a problem */
|
||||||
};
|
};
|
||||||
|
@@ -50,6 +50,9 @@
|
|||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_idprop.h"
|
#include "BKE_idprop.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
@@ -66,8 +69,6 @@
|
|||||||
#include "ED_view3d.h"
|
#include "ED_view3d.h"
|
||||||
#include "ED_util.h"
|
#include "ED_util.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
|
|
||||||
#include "GPU_debug.h"
|
#include "GPU_debug.h"
|
||||||
|
|
||||||
#include "UI_interface.h"
|
#include "UI_interface.h"
|
||||||
|
@@ -554,7 +554,11 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
|
|||||||
|
|
||||||
/* confusing this global... */
|
/* confusing this global... */
|
||||||
G.relbase_valid = 1;
|
G.relbase_valid = 1;
|
||||||
retval = BKE_blendfile_read(C, filepath, reports);
|
retval = BKE_blendfile_read(C, filepath, reports);
|
||||||
|
|
||||||
|
printf("Updating assets for: %s\n", filepath);
|
||||||
|
WM_operator_name_call(C, "WM_OT_assets_update_check", WM_OP_EXEC_DEFAULT, NULL);
|
||||||
|
|
||||||
/* when loading startup.blend's, we can be left with a blank path */
|
/* when loading startup.blend's, we can be left with a blank path */
|
||||||
if (G.main->name[0]) {
|
if (G.main->name[0]) {
|
||||||
G.save_over = 1;
|
G.save_over = 1;
|
||||||
@@ -694,6 +698,9 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
|
|||||||
if (!from_memory) {
|
if (!from_memory) {
|
||||||
if (BLI_access(startstr, R_OK) == 0) {
|
if (BLI_access(startstr, R_OK) == 0) {
|
||||||
success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
|
success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
|
||||||
|
|
||||||
|
printf("Updating assets for: %s\n", startstr);
|
||||||
|
WM_operator_name_call(C, "WM_OT_assets_update_check", WM_OP_EXEC_DEFAULT, NULL);
|
||||||
}
|
}
|
||||||
if (BLI_listbase_is_empty(&U.themes)) {
|
if (BLI_listbase_is_empty(&U.themes)) {
|
||||||
if (G.debug & G_DEBUG)
|
if (G.debug & G_DEBUG)
|
||||||
|
@@ -44,9 +44,11 @@
|
|||||||
#include "DNA_ID.h"
|
#include "DNA_ID.h"
|
||||||
#include "DNA_screen_types.h"
|
#include "DNA_screen_types.h"
|
||||||
#include "DNA_scene_types.h"
|
#include "DNA_scene_types.h"
|
||||||
|
#include "DNA_space_types.h"
|
||||||
#include "DNA_windowmanager_types.h"
|
#include "DNA_windowmanager_types.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
#include "RNA_define.h"
|
||||||
|
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
#include "BLI_bitmap.h"
|
#include "BLI_bitmap.h"
|
||||||
@@ -56,16 +58,21 @@
|
|||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
#include "BLI_ghash.h"
|
#include "BLI_ghash.h"
|
||||||
|
|
||||||
|
#include "PIL_time.h"
|
||||||
|
|
||||||
#include "BLO_readfile.h"
|
#include "BLO_readfile.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_depsgraph.h"
|
#include "BKE_depsgraph.h"
|
||||||
#include "BKE_library.h"
|
#include "BKE_library.h"
|
||||||
#include "BKE_library_remap.h"
|
#include "BKE_library_remap.h"
|
||||||
#include "BKE_global.h"
|
#include "BKE_global.h"
|
||||||
|
#include "BKE_image.h"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_report.h"
|
#include "BKE_report.h"
|
||||||
#include "BKE_scene.h"
|
#include "BKE_scene.h"
|
||||||
|
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
|
||||||
|
|
||||||
#include "BKE_idcode.h"
|
#include "BKE_idcode.h"
|
||||||
|
|
||||||
@@ -73,13 +80,10 @@
|
|||||||
#include "IMB_colormanagement.h"
|
#include "IMB_colormanagement.h"
|
||||||
|
|
||||||
#include "ED_screen.h"
|
#include "ED_screen.h"
|
||||||
|
#include "ED_fileselect.h"
|
||||||
|
|
||||||
#include "GPU_material.h"
|
#include "GPU_material.h"
|
||||||
|
|
||||||
#include "RNA_access.h"
|
|
||||||
#include "RNA_define.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
#include "WM_types.h"
|
#include "WM_types.h"
|
||||||
|
|
||||||
@@ -144,6 +148,7 @@ static short wm_link_append_flag(wmOperator *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct WMLinkAppendDataItem {
|
typedef struct WMLinkAppendDataItem {
|
||||||
|
AssetUUID *uuid;
|
||||||
char *name;
|
char *name;
|
||||||
BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
|
BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
|
||||||
short idcode;
|
short idcode;
|
||||||
@@ -153,6 +158,7 @@ typedef struct WMLinkAppendDataItem {
|
|||||||
} WMLinkAppendDataItem;
|
} WMLinkAppendDataItem;
|
||||||
|
|
||||||
typedef struct WMLinkAppendData {
|
typedef struct WMLinkAppendData {
|
||||||
|
const char *root;
|
||||||
LinkNodePair libraries;
|
LinkNodePair libraries;
|
||||||
LinkNodePair items;
|
LinkNodePair items;
|
||||||
int num_libraries;
|
int num_libraries;
|
||||||
@@ -192,11 +198,18 @@ static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const c
|
|||||||
}
|
}
|
||||||
|
|
||||||
static WMLinkAppendDataItem *wm_link_append_data_item_add(
|
static WMLinkAppendDataItem *wm_link_append_data_item_add(
|
||||||
WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata)
|
WMLinkAppendData *lapp_data, const char *idname, const short idcode, const AssetUUID *uuid, void *customdata)
|
||||||
{
|
{
|
||||||
WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
|
WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
|
||||||
size_t len = strlen(idname) + 1;
|
const size_t len = strlen(idname) + 1;
|
||||||
|
|
||||||
|
if (uuid) {
|
||||||
|
item->uuid = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item->uuid));
|
||||||
|
*item->uuid = *uuid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item->uuid = NULL;
|
||||||
|
}
|
||||||
item->name = BLI_memarena_alloc(lapp_data->memarena, len);
|
item->name = BLI_memarena_alloc(lapp_data->memarena, len);
|
||||||
BLI_strncpy(item->name, idname, len);
|
BLI_strncpy(item->name, idname, len);
|
||||||
item->idcode = idcode;
|
item->idcode = idcode;
|
||||||
@@ -211,8 +224,80 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int path_to_idcode(const char *path)
|
||||||
|
{
|
||||||
|
const int filetype = ED_path_extension_type(path);
|
||||||
|
switch (filetype) {
|
||||||
|
case FILE_TYPE_IMAGE:
|
||||||
|
case FILE_TYPE_MOVIE:
|
||||||
|
return ID_IM;
|
||||||
|
case FILE_TYPE_FTFONT:
|
||||||
|
return ID_VF;
|
||||||
|
case FILE_TYPE_SOUND:
|
||||||
|
return ID_SO;
|
||||||
|
case FILE_TYPE_PYSCRIPT:
|
||||||
|
case FILE_TYPE_TEXT:
|
||||||
|
return ID_TXT;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_link_virtual_lib(WMLinkAppendData *lapp_data, Main *bmain, AssetEngineType *aet, const int lib_idx)
|
||||||
|
{
|
||||||
|
LinkNode *itemlink;
|
||||||
|
int item_idx;
|
||||||
|
|
||||||
|
BLI_assert(aet);
|
||||||
|
|
||||||
|
/* Find or add virtual library matching current asset engine. */
|
||||||
|
Library *virtlib = BKE_library_asset_virtual_ensure(bmain, aet);
|
||||||
|
|
||||||
|
for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
|
||||||
|
WMLinkAppendDataItem *item = itemlink->link;
|
||||||
|
ID *new_id = NULL;
|
||||||
|
bool id_exists = false;
|
||||||
|
|
||||||
|
if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item->idcode) {
|
||||||
|
case ID_IM:
|
||||||
|
new_id = (ID *)BKE_image_load_exists_ex(item->name, &id_exists);
|
||||||
|
if (id_exists) {
|
||||||
|
if (!new_id->uuid || !ASSETUUID_COMPARE(new_id->uuid, item->uuid)) {
|
||||||
|
/* Fake 'same ID' (same path, but different uuid or whatever), force loading into new ID. */
|
||||||
|
BLI_assert(new_id->lib != virtlib);
|
||||||
|
new_id = (ID *)BKE_image_load(bmain, item->name);
|
||||||
|
id_exists = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_id) {
|
||||||
|
new_id->lib = virtlib;
|
||||||
|
new_id->tag |= LIB_TAG_EXTERN | LIB_ASSET;
|
||||||
|
|
||||||
|
if (!id_exists) {
|
||||||
|
new_id->uuid = MEM_mallocN(sizeof(*new_id->uuid), __func__);
|
||||||
|
*new_id->uuid = *item->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the link is sucessful, clear item's libs 'todo' flags.
|
||||||
|
* This avoids trying to link same item with other libraries to come. */
|
||||||
|
BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
|
||||||
|
item->new_id = new_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BKE_libraries_asset_repositories_rebuild(bmain);
|
||||||
|
}
|
||||||
|
|
||||||
static void wm_link_do(
|
static void wm_link_do(
|
||||||
WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d,
|
WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, AssetEngineType *aet, Scene *scene, View3D *v3d,
|
||||||
const bool use_placeholders, const bool force_indirect)
|
const bool use_placeholders, const bool force_indirect)
|
||||||
{
|
{
|
||||||
Main *mainl;
|
Main *mainl;
|
||||||
@@ -229,6 +314,12 @@ static void wm_link_do(
|
|||||||
for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
|
for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
|
||||||
char *libname = liblink->link;
|
char *libname = liblink->link;
|
||||||
|
|
||||||
|
if (libname[0] == '\0') {
|
||||||
|
/* Special 'virtual lib' cases. */
|
||||||
|
wm_link_virtual_lib(lapp_data, bmain, aet, lib_idx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bh = BLO_blendhandle_from_file(libname, reports);
|
bh = BLO_blendhandle_from_file(libname, reports);
|
||||||
|
|
||||||
if (bh == NULL) {
|
if (bh == NULL) {
|
||||||
@@ -260,8 +351,9 @@ static void wm_link_do(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_id = BLO_library_link_named_part_ex(
|
new_id = BLO_library_link_named_part_asset(
|
||||||
mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect);
|
mainl, &bh, aet, lapp_data->root, item->idcode, item->name, item->uuid, flag, scene, v3d,
|
||||||
|
use_placeholders, force_indirect);
|
||||||
|
|
||||||
if (new_id) {
|
if (new_id) {
|
||||||
/* If the link is successful, clear item's libs 'todo' flags.
|
/* If the link is successful, clear item's libs 'todo' flags.
|
||||||
@@ -287,21 +379,30 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||||||
int totfiles = 0;
|
int totfiles = 0;
|
||||||
short flag;
|
short flag;
|
||||||
|
|
||||||
|
char asset_engine[BKE_ST_MAXNAME];
|
||||||
|
AssetEngineType *aet = NULL;
|
||||||
|
AssetUUID uuid = {0};
|
||||||
|
|
||||||
RNA_string_get(op->ptr, "filename", relname);
|
RNA_string_get(op->ptr, "filename", relname);
|
||||||
RNA_string_get(op->ptr, "directory", root);
|
RNA_string_get(op->ptr, "directory", root);
|
||||||
|
|
||||||
BLI_join_dirfile(path, sizeof(path), root, relname);
|
BLI_join_dirfile(path, sizeof(path), root, relname);
|
||||||
|
|
||||||
|
RNA_string_get(op->ptr, "asset_engine", asset_engine);
|
||||||
|
if (asset_engine[0] != '\0') {
|
||||||
|
aet = BKE_asset_engines_find(asset_engine);
|
||||||
|
}
|
||||||
|
|
||||||
/* test if we have a valid data */
|
/* test if we have a valid data */
|
||||||
if (!BLO_library_path_explode(path, libname, &group, &name)) {
|
if (!BLO_library_path_explode(path, libname, &group, &name) && (!aet || !path_to_idcode(path))) {
|
||||||
BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
|
BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
else if (!group) {
|
else if (!group && !aet) {
|
||||||
BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
|
BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
else if (BLI_path_cmp(bmain->name, libname) == 0) {
|
else if (libname[0] && BLI_path_cmp(bmain->name, libname) == 0) {
|
||||||
BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
|
BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
@@ -347,6 +448,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||||||
/* We define our working data...
|
/* We define our working data...
|
||||||
* Note that here, each item 'uses' one library, and only one. */
|
* Note that here, each item 'uses' one library, and only one. */
|
||||||
lapp_data = wm_link_append_data_new(flag);
|
lapp_data = wm_link_append_data_new(flag);
|
||||||
|
lapp_data->root = root;
|
||||||
if (totfiles != 0) {
|
if (totfiles != 0) {
|
||||||
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
|
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
|
||||||
int lib_idx = 0;
|
int lib_idx = 0;
|
||||||
@@ -368,6 +470,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||||||
wm_link_append_data_library_add(lapp_data, libname);
|
wm_link_append_data_library_add(lapp_data, libname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Non-blend paths are only valid in asset engine context (virtual libraries). */
|
||||||
|
else if (aet && path_to_idcode(path)) {
|
||||||
|
if (!BLI_ghash_haskey(libraries, "")) {
|
||||||
|
BLI_ghash_insert(libraries, BLI_strdup(""), SET_INT_IN_POINTER(lib_idx));
|
||||||
|
lib_idx++;
|
||||||
|
wm_link_append_data_library_add(lapp_data, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RNA_END;
|
RNA_END;
|
||||||
|
|
||||||
@@ -386,26 +496,47 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
|
lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
|
||||||
|
|
||||||
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
|
if (aet) {
|
||||||
|
RNA_int_get_array(&itemptr, "asset_uuid", uuid.uuid_asset);
|
||||||
|
RNA_int_get_array(&itemptr, "variant_uuid", uuid.uuid_variant);
|
||||||
|
RNA_int_get_array(&itemptr, "revision_uuid", uuid.uuid_revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), &uuid, NULL);
|
||||||
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
|
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
|
||||||
}
|
}
|
||||||
|
else if (aet) { /* Non-blend paths are only valid in asset engine context (virtual libraries). */
|
||||||
|
const int idcode = path_to_idcode(path);
|
||||||
|
|
||||||
|
if (idcode != 0) {
|
||||||
|
WMLinkAppendDataItem *item;
|
||||||
|
lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, ""));
|
||||||
|
|
||||||
|
RNA_int_get_array(&itemptr, "asset_uuid", uuid.uuid_asset);
|
||||||
|
RNA_int_get_array(&itemptr, "variant_uuid", uuid.uuid_variant);
|
||||||
|
RNA_int_get_array(&itemptr, "revision_uuid", uuid.uuid_revision);
|
||||||
|
|
||||||
|
item = wm_link_append_data_item_add(lapp_data, path, idcode, &uuid, NULL);
|
||||||
|
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RNA_END;
|
RNA_END;
|
||||||
|
|
||||||
BLI_ghash_free(libraries, MEM_freeN, NULL);
|
BLI_ghash_free(libraries, MEM_freeN, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else if (group && name) {
|
||||||
WMLinkAppendDataItem *item;
|
WMLinkAppendDataItem *item;
|
||||||
|
|
||||||
wm_link_append_data_library_add(lapp_data, libname);
|
wm_link_append_data_library_add(lapp_data, libname);
|
||||||
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
|
item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), &uuid, NULL);
|
||||||
BLI_BITMAP_ENABLE(item->libraries, 0);
|
BLI_BITMAP_ENABLE(item->libraries, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX We'd need re-entrant locking on Main for this to work... */
|
/* XXX We'd need re-entrant locking on Main for this to work... */
|
||||||
/* BKE_main_lock(bmain); */
|
/* BKE_main_lock(bmain); */
|
||||||
|
|
||||||
wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false);
|
wm_link_do(lapp_data, op->reports, bmain, aet, scene, CTX_wm_view3d(C), false, false);
|
||||||
|
|
||||||
/* BKE_main_unlock(bmain); */
|
/* BKE_main_unlock(bmain); */
|
||||||
|
|
||||||
@@ -465,6 +596,10 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
|
|||||||
|
|
||||||
/* better not save _any_ settings for this operator */
|
/* better not save _any_ settings for this operator */
|
||||||
/* properties */
|
/* properties */
|
||||||
|
prop = RNA_def_string(ot->srna, "asset_engine", NULL, sizeof(((AssetEngineType *)NULL)->idname),
|
||||||
|
"Asset Engine", "Asset engine identifier used to append/link the data");
|
||||||
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
|
||||||
|
|
||||||
prop = RNA_def_boolean(ot->srna, "link", is_link,
|
prop = RNA_def_boolean(ot->srna, "link", is_link,
|
||||||
"Link", "Link the objects or datablocks rather than appending");
|
"Link", "Link the objects or datablocks rather than appending");
|
||||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
|
||||||
@@ -541,6 +676,11 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
|
|||||||
"Cannot relocate indirectly linked library '%s'", lib->filepath);
|
"Cannot relocate indirectly linked library '%s'", lib->filepath);
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
if (lib->flag & LIBRARY_FLAG_VIRTUAL) {
|
||||||
|
BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
|
||||||
|
"Cannot relocate virtual library '%s'", lib->id.name + 2);
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
RNA_string_set(op->ptr, "filepath", lib->filepath);
|
RNA_string_set(op->ptr, "filepath", lib->filepath);
|
||||||
|
|
||||||
WM_event_add_fileselect(C, op);
|
WM_event_add_fileselect(C, op);
|
||||||
@@ -551,9 +691,13 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
|
|||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \param library if given, all IDs from that library will be removed and reloaded. Otherwise, IDs must have already
|
||||||
|
* been removed from \a bmain, and added to \a lapp_data.
|
||||||
|
*/
|
||||||
static void lib_relocate_do(
|
static void lib_relocate_do(
|
||||||
Main *bmain, Scene *scene,
|
Main *bmain, Scene *scene,
|
||||||
Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload)
|
Library *library, WMLinkAppendData *lapp_data, ReportList *reports, AssetEngineType *aet, const bool do_reload)
|
||||||
{
|
{
|
||||||
ListBase *lbarray[MAX_LIBARRAY];
|
ListBase *lbarray[MAX_LIBARRAY];
|
||||||
int lba_idx;
|
int lba_idx;
|
||||||
@@ -562,29 +706,31 @@ static void lib_relocate_do(
|
|||||||
int item_idx;
|
int item_idx;
|
||||||
|
|
||||||
/* Remove all IDs to be reloaded from Main. */
|
/* Remove all IDs to be reloaded from Main. */
|
||||||
lba_idx = set_listbasepointers(bmain, lbarray);
|
if (library) {
|
||||||
while (lba_idx--) {
|
lba_idx = set_listbasepointers(bmain, lbarray);
|
||||||
ID *id = lbarray[lba_idx]->first;
|
while (lba_idx--) {
|
||||||
const short idcode = id ? GS(id->name) : 0;
|
ID *id = lbarray[lba_idx]->first;
|
||||||
|
const short idcode = id ? GS(id->name) : 0;
|
||||||
|
|
||||||
if (!id || !BKE_idcode_is_linkable(idcode)) {
|
if (!id || !BKE_idcode_is_linkable(idcode)) {
|
||||||
/* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
|
/* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; id; id = id->next) {
|
for (; id; id = id->next) {
|
||||||
if (id->lib == library) {
|
if (id->lib == library) {
|
||||||
WMLinkAppendDataItem *item;
|
WMLinkAppendDataItem *item;
|
||||||
|
|
||||||
/* We remove it from current Main, and add it to items to link... */
|
/* We remove it from current Main, and add it to items to link... */
|
||||||
/* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
|
/* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
|
||||||
BLI_remlink(lbarray[lba_idx], id);
|
BLI_remlink(lbarray[lba_idx], id);
|
||||||
item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
|
item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, NULL, id);
|
||||||
BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
|
BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
|
||||||
|
|
||||||
#ifdef PRINT_DEBUG
|
#ifdef PRINT_DEBUG
|
||||||
printf("\tdatablock to seek for: %s\n", id->name);
|
printf("\tdatablock to seek for: %s\n", id->name);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -592,7 +738,7 @@ static void lib_relocate_do(
|
|||||||
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
|
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
|
||||||
|
|
||||||
/* We do not want any instanciation here! */
|
/* We do not want any instanciation here! */
|
||||||
wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload);
|
wm_link_do(lapp_data, reports, bmain, aet, NULL, NULL, do_reload, do_reload);
|
||||||
|
|
||||||
BKE_main_lock(bmain);
|
BKE_main_lock(bmain);
|
||||||
|
|
||||||
@@ -759,7 +905,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
|
|||||||
|
|
||||||
wm_link_append_data_library_add(lapp_data, lib->filepath);
|
wm_link_append_data_library_add(lapp_data, lib->filepath);
|
||||||
|
|
||||||
lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, true);
|
lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, NULL, true);
|
||||||
|
|
||||||
wm_link_append_data_free(lapp_data);
|
wm_link_append_data_free(lapp_data);
|
||||||
|
|
||||||
@@ -792,6 +938,11 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
|
|||||||
"Cannot relocate indirectly linked library '%s'", lib->filepath);
|
"Cannot relocate indirectly linked library '%s'", lib->filepath);
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
if (lib->flag & LIBRARY_FLAG_VIRTUAL) {
|
||||||
|
BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT,
|
||||||
|
"Cannot relocate or reload virtual library '%s'", lib->id.name + 2);
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
RNA_string_get(op->ptr, "directory", root);
|
RNA_string_get(op->ptr, "directory", root);
|
||||||
RNA_string_get(op->ptr, "filename", libname);
|
RNA_string_get(op->ptr, "filename", libname);
|
||||||
@@ -866,7 +1017,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, do_reload);
|
lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, NULL, do_reload);
|
||||||
|
|
||||||
wm_link_append_data_free(lapp_data);
|
wm_link_append_data_free(lapp_data);
|
||||||
|
|
||||||
@@ -934,4 +1085,451 @@ void WM_OT_lib_reload(wmOperatorType *ot)
|
|||||||
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
|
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \name Asset-related operators.
|
||||||
|
*
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
typedef struct AssetUpdateCheckEngine {
|
||||||
|
struct AssetUpdateCheckEngine *next, *prev;
|
||||||
|
AssetEngine *ae;
|
||||||
|
|
||||||
|
/* Note: We cannot store IDs themselves in non-locking async task... so we'll have to check again for
|
||||||
|
* UUID/IDs mapping on each update call... Not ideal, but don't think it will be that big of a bottleneck
|
||||||
|
* in practice. */
|
||||||
|
AssetUUIDList uuids;
|
||||||
|
int allocated_uuids;
|
||||||
|
int ae_job_id;
|
||||||
|
short status;
|
||||||
|
} AssetUpdateCheckEngine;
|
||||||
|
|
||||||
|
typedef struct AssetUpdateCheckJob {
|
||||||
|
ListBase engines;
|
||||||
|
short flag;
|
||||||
|
|
||||||
|
float *progress;
|
||||||
|
short *stop;
|
||||||
|
} AssetUpdateCheckJob;
|
||||||
|
|
||||||
|
/* AssetUpdateCheckEngine.status */
|
||||||
|
enum {
|
||||||
|
AUCE_UPDATE_CHECK_DONE = 1 << 0, /* Update check is finished for this engine. */
|
||||||
|
AUCE_ENSURE_ASSETS_DONE = 1 << 1, /* Asset ensure is finished for this engine (if applicable). */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* AssetUpdateCheckJob.flag */
|
||||||
|
enum {
|
||||||
|
AUCJ_ENSURE_ASSETS = 1 << 0, /* Try to perform the 'ensure' task too. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper to fetch a set of assets to handle, regrouped by asset engine. */
|
||||||
|
static void asset_update_engines_uuids_fetch(
|
||||||
|
ListBase *engines,
|
||||||
|
Main *bmain, AssetUUIDList *uuids, const short uuid_tags,
|
||||||
|
const bool do_reset_tags)
|
||||||
|
{
|
||||||
|
for (Library *lib = bmain->library.first; lib; lib = lib->id.next) {
|
||||||
|
if (lib->asset_repository) {
|
||||||
|
printf("Checking lib file '%s' (engine %s, ver. %d)\n", lib->filepath,
|
||||||
|
lib->asset_repository->asset_engine, lib->asset_repository->asset_engine_version);
|
||||||
|
|
||||||
|
AssetUpdateCheckEngine *auce = NULL;
|
||||||
|
AssetEngineType *ae_type = BKE_asset_engines_find(lib->asset_repository->asset_engine);
|
||||||
|
bool copy_engine = false;
|
||||||
|
|
||||||
|
if (ae_type == NULL) {
|
||||||
|
printf("ERROR! Unknown asset engine!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
|
||||||
|
ID *id = ((LinkData *)aref->id_list.first)->data;
|
||||||
|
BLI_assert(id->uuid);
|
||||||
|
|
||||||
|
if (uuid_tags && !(id->uuid->tag & uuid_tags)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuids) {
|
||||||
|
int i = uuids->nbr_uuids;
|
||||||
|
bool skip = true;
|
||||||
|
for (AssetUUID *uuid = uuids->uuids; i--; uuid++) {
|
||||||
|
if (ASSETUUID_COMPARE(id->uuid, uuid)) {
|
||||||
|
skip = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ae_type == NULL) {
|
||||||
|
if (do_reset_tags) {
|
||||||
|
id->uuid->tag = UUID_TAG_ENGINE_MISSING;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id->uuid->tag |= UUID_TAG_ENGINE_MISSING;
|
||||||
|
}
|
||||||
|
G.f |= G_ASSETS_FAIL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auce == NULL) {
|
||||||
|
for (auce = engines->first; auce; auce = auce->next) {
|
||||||
|
if (auce->ae->type == ae_type) {
|
||||||
|
/* In case we have several engine versions for the same engine, we create several
|
||||||
|
* AssetUpdateCheckEngine structs (since an uuid list can only handle one ae version), using
|
||||||
|
* the same (shallow) copy of the actual asset engine. */
|
||||||
|
copy_engine = (auce->uuids.asset_engine_version != lib->asset_repository->asset_engine_version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copy_engine || auce == NULL) {
|
||||||
|
AssetUpdateCheckEngine *auce_prev = auce;
|
||||||
|
auce = MEM_callocN(sizeof(*auce), __func__);
|
||||||
|
auce->ae = copy_engine ? BKE_asset_engine_copy(auce_prev->ae) :
|
||||||
|
BKE_asset_engine_create(ae_type, NULL);
|
||||||
|
auce->ae_job_id = AE_JOB_ID_UNSET;
|
||||||
|
auce->uuids.asset_engine_version = lib->asset_repository->asset_engine_version;
|
||||||
|
BLI_addtail(engines, auce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\tWe need to check for updated asset %s...\n", id->name);
|
||||||
|
if (do_reset_tags) {
|
||||||
|
id->uuid->tag = (id->tag & LIB_TAG_MISSING) ? UUID_TAG_ASSET_MISSING : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auce->uuids.nbr_uuids++;
|
||||||
|
BKE_asset_uuid_print(id->uuid);
|
||||||
|
if (auce->uuids.nbr_uuids > auce->allocated_uuids) {
|
||||||
|
auce->allocated_uuids += 16;
|
||||||
|
BLI_assert(auce->uuids.nbr_uuids < auce->allocated_uuids);
|
||||||
|
|
||||||
|
const size_t allocsize = sizeof(*auce->uuids.uuids) * (size_t)auce->allocated_uuids;
|
||||||
|
auce->uuids.uuids = auce->uuids.uuids ?
|
||||||
|
MEM_reallocN_id(auce->uuids.uuids, allocsize, __func__) :
|
||||||
|
MEM_mallocN(allocsize, __func__);
|
||||||
|
}
|
||||||
|
auce->uuids.uuids[auce->uuids.nbr_uuids - 1] = *id->uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asset_updatecheck_startjob(void *aucjv, short *stop, short *do_update, float *progress)
|
||||||
|
{
|
||||||
|
AssetUpdateCheckJob *aucj = aucjv;
|
||||||
|
|
||||||
|
aucj->progress = progress;
|
||||||
|
aucj->stop = stop;
|
||||||
|
/* Using AE engine, worker thread here is just sleeping! */
|
||||||
|
while (!*stop) {
|
||||||
|
*do_update = true;
|
||||||
|
PIL_sleep_ms(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asset_updatecheck_update(void *aucjv)
|
||||||
|
{
|
||||||
|
AssetUpdateCheckJob *aucj = aucjv;
|
||||||
|
Main *bmain = G.main;
|
||||||
|
|
||||||
|
const bool do_ensure = ((aucj->flag & AUCJ_ENSURE_ASSETS) != 0);
|
||||||
|
bool is_finished = true;
|
||||||
|
int nbr_engines = 0;
|
||||||
|
|
||||||
|
*aucj->progress = 0.0f;
|
||||||
|
|
||||||
|
/* TODO need to take care of 'broken' engines that error - in this case we probably want to cancel the whole
|
||||||
|
* update process over effected libraries' data... */
|
||||||
|
for (AssetUpdateCheckEngine *auce = aucj->engines.first; auce; auce = auce->next, nbr_engines++) {
|
||||||
|
AssetEngine *ae = auce->ae;
|
||||||
|
AssetEngineType *ae_type = ae->type;
|
||||||
|
|
||||||
|
/* Step 1: we ask asset engine about status of all asset IDs from it. */
|
||||||
|
if (!(auce->status & AUCE_UPDATE_CHECK_DONE)) {
|
||||||
|
auce->ae_job_id = ae_type->update_check(ae, auce->ae_job_id, &auce->uuids);
|
||||||
|
if (auce->ae_job_id == AE_JOB_ID_INVALID) { /* Immediate execution. */
|
||||||
|
*aucj->progress += 1.0f;
|
||||||
|
auce->status |= AUCE_UPDATE_CHECK_DONE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*aucj->progress += ae_type->progress(ae, auce->ae_job_id);
|
||||||
|
if ((ae_type->status(ae, auce->ae_job_id) & (AE_STATUS_RUNNING | AE_STATUS_VALID)) !=
|
||||||
|
(AE_STATUS_RUNNING | AE_STATUS_VALID))
|
||||||
|
{
|
||||||
|
auce->status |= AUCE_UPDATE_CHECK_DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auce->status & AUCE_UPDATE_CHECK_DONE) {
|
||||||
|
auce->ae_job_id = AE_JOB_ID_UNSET;
|
||||||
|
|
||||||
|
for (Library *lib = bmain->library.first; lib; lib = lib->id.next) {
|
||||||
|
if (!lib->asset_repository ||
|
||||||
|
(BKE_asset_engines_find(lib->asset_repository->asset_engine) != ae_type))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UUIDs returned by update_check are assumed to be valid (one way or the other) in current
|
||||||
|
* asset engine version. */
|
||||||
|
lib->asset_repository->asset_engine_version = ae_type->version;
|
||||||
|
|
||||||
|
int i = auce->uuids.nbr_uuids;
|
||||||
|
for (AssetUUID *uuid = auce->uuids.uuids; i--; uuid++) {
|
||||||
|
for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
|
||||||
|
ID *id = ((LinkData *)aref->id_list.first)->data;
|
||||||
|
BLI_assert(id->uuid);
|
||||||
|
if (ASSETUUID_COMPARE(id->uuid, uuid)) {
|
||||||
|
*id->uuid = *uuid;
|
||||||
|
|
||||||
|
if (id->uuid->tag & UUID_TAG_ENGINE_MISSING) {
|
||||||
|
G.f |= G_ASSETS_FAIL;
|
||||||
|
printf("\t%s uses a currently unknown asset engine!\n", id->name);
|
||||||
|
}
|
||||||
|
else if (id->uuid->tag & UUID_TAG_ASSET_MISSING) {
|
||||||
|
G.f |= G_ASSETS_FAIL;
|
||||||
|
printf("\t%s is currently unknown by asset engine!\n", id->name);
|
||||||
|
}
|
||||||
|
else if (id->uuid->tag & UUID_TAG_ASSET_RELOAD) {
|
||||||
|
G.f |= G_ASSETS_NEED_RELOAD;
|
||||||
|
printf("\t%s needs to be reloaded/updated!\n", id->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 2: If required and supported, we 'ensure' assets tagged as to be reloaded. */
|
||||||
|
if (do_ensure && !(auce->status & AUCE_ENSURE_ASSETS_DONE) && ae_type->ensure_uuids != NULL) {
|
||||||
|
/* TODO ensure entries! */
|
||||||
|
*aucj->progress += 1.0f;
|
||||||
|
auce->status |= AUCE_ENSURE_ASSETS_DONE;
|
||||||
|
if (auce->status & AUCE_ENSURE_ASSETS_DONE) {
|
||||||
|
auce->ae_job_id = AE_JOB_ID_UNSET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((auce->status & (AUCE_UPDATE_CHECK_DONE | AUCE_ENSURE_ASSETS_DONE)) !=
|
||||||
|
(AUCE_UPDATE_CHECK_DONE | AUCE_ENSURE_ASSETS_DONE))
|
||||||
|
{
|
||||||
|
is_finished = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*aucj->progress /= (float)(do_ensure ? nbr_engines * 2 : nbr_engines);
|
||||||
|
*aucj->stop = is_finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asset_updatecheck_endjob(void *aucjv)
|
||||||
|
{
|
||||||
|
AssetUpdateCheckJob *aucj = aucjv;
|
||||||
|
|
||||||
|
/* In case there would be some dangling update. */
|
||||||
|
asset_updatecheck_update(aucjv);
|
||||||
|
|
||||||
|
for (AssetUpdateCheckEngine *auce = aucj->engines.first; auce; auce = auce->next) {
|
||||||
|
AssetEngine *ae = auce->ae;
|
||||||
|
if (!ELEM(auce->ae_job_id, AE_JOB_ID_INVALID, AE_JOB_ID_UNSET)) {
|
||||||
|
ae->type->kill(ae, auce->ae_job_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asset_updatecheck_free(void *aucjv)
|
||||||
|
{
|
||||||
|
AssetUpdateCheckJob *aucj = aucjv;
|
||||||
|
|
||||||
|
for (AssetUpdateCheckEngine *auce = aucj->engines.first; auce; auce = auce->next) {
|
||||||
|
BKE_asset_engine_free(auce->ae);
|
||||||
|
MEM_freeN(auce->uuids.uuids);
|
||||||
|
}
|
||||||
|
BLI_freelistN(&aucj->engines);
|
||||||
|
|
||||||
|
MEM_freeN(aucj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asset_updatecheck_start(const bContext *C)
|
||||||
|
{
|
||||||
|
wmJob *wm_job;
|
||||||
|
AssetUpdateCheckJob *aucj;
|
||||||
|
|
||||||
|
Main *bmain = CTX_data_main(C);
|
||||||
|
|
||||||
|
/* prepare job data */
|
||||||
|
aucj = MEM_callocN(sizeof(*aucj), __func__);
|
||||||
|
|
||||||
|
G.f &= ~(G_ASSETS_FAIL | G_ASSETS_NEED_RELOAD | G_ASSETS_QUIET);
|
||||||
|
|
||||||
|
/* Get all assets' uuids, grouped by asset engine/versions - and with cleared status tags. */
|
||||||
|
asset_update_engines_uuids_fetch(&aucj->engines, bmain, NULL, 0, true);
|
||||||
|
|
||||||
|
/* Early out if there is nothing to do! */
|
||||||
|
if (BLI_listbase_is_empty(&aucj->engines)) {
|
||||||
|
asset_updatecheck_free(aucj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup job */
|
||||||
|
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Checking for asset updates...",
|
||||||
|
WM_JOB_PROGRESS, WM_JOB_TYPE_ASSET_UPDATECHECK);
|
||||||
|
WM_jobs_customdata_set(wm_job, aucj, asset_updatecheck_free);
|
||||||
|
WM_jobs_timer(wm_job, 0.1, 0, 0/*NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST*/); /* TODO probably outliner stuff once UI is defined for this! */
|
||||||
|
WM_jobs_callbacks(wm_job, asset_updatecheck_startjob, NULL, asset_updatecheck_update, asset_updatecheck_endjob);
|
||||||
|
|
||||||
|
/* start the job */
|
||||||
|
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wm_assets_update_check_exec(bContext *C, wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
asset_updatecheck_start(C);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WM_OT_assets_update_check(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Check Assets Update";
|
||||||
|
ot->idname = "WM_OT_assets_update_check";
|
||||||
|
ot->description = "Check/refresh status of assets (in a background job)";
|
||||||
|
|
||||||
|
ot->exec = wm_assets_update_check_exec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wm_assets_reload_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
/* We need to:
|
||||||
|
* - get list of all asset IDs to reload (either via given uuids, or their tag), and regroup them by asset engine.
|
||||||
|
* - tag somehow all their indirect 'dependencies' IDs.
|
||||||
|
* - call load_pre to get actual filepaths.
|
||||||
|
* - do reload/relocate and remap as in lib_reload.
|
||||||
|
* - cleanup indirect dependencies IDs with zero users.
|
||||||
|
*/
|
||||||
|
Main *bmain = CTX_data_main(C);
|
||||||
|
Scene *scene = CTX_data_scene(C);
|
||||||
|
|
||||||
|
ListBase engines = {NULL};
|
||||||
|
|
||||||
|
/* For now, ignore the uuids list of op. */
|
||||||
|
asset_update_engines_uuids_fetch(&engines, bmain, NULL, UUID_TAG_ASSET_RELOAD, false);
|
||||||
|
|
||||||
|
for (AssetUpdateCheckEngine *auce = engines.first; auce; auce = auce->next) {
|
||||||
|
FileDirEntryArr *paths = BKE_asset_engine_uuids_load_pre(auce->ae, &auce->uuids);
|
||||||
|
FileDirEntry *en;
|
||||||
|
AssetUUID *uuid;
|
||||||
|
|
||||||
|
char path[FILE_MAX_LIBEXTRA], libname[FILE_MAX];
|
||||||
|
char *group, *name;
|
||||||
|
|
||||||
|
short flag = 0;
|
||||||
|
bool do_reload = true;
|
||||||
|
|
||||||
|
WMLinkAppendData *lapp_data = wm_link_append_data_new(flag);
|
||||||
|
lapp_data->root = paths->root;
|
||||||
|
|
||||||
|
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
|
||||||
|
int lib_idx = 0;
|
||||||
|
|
||||||
|
printf("Engine %s (ver. %d) returned root path '%s'\n", auce->ae->type->name, auce->ae->type->version, paths->root);
|
||||||
|
for (en = paths->entries.first; en; en = en->next) {
|
||||||
|
printf("\t-> %s\n", en->relpath);
|
||||||
|
|
||||||
|
BLI_join_dirfile(path, sizeof(path), paths->root, en->relpath);
|
||||||
|
|
||||||
|
if (BLO_library_path_explode(path, libname, &group, &name)) {
|
||||||
|
BLI_assert(group && name);
|
||||||
|
|
||||||
|
if (!BLI_ghash_haskey(libraries, libname)) {
|
||||||
|
BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
|
||||||
|
lib_idx++;
|
||||||
|
wm_link_append_data_library_add(lapp_data, libname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Non-blend paths are only valid in asset engine context (virtual libraries). */
|
||||||
|
else if (path_to_idcode(path)) {
|
||||||
|
if (!BLI_ghash_haskey(libraries, "")) {
|
||||||
|
BLI_ghash_insert(libraries, BLI_strdup(""), SET_INT_IN_POINTER(lib_idx));
|
||||||
|
lib_idx++;
|
||||||
|
wm_link_append_data_library_add(lapp_data, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (en = paths->entries.first, uuid = auce->uuids.uuids; en; en = en->next, uuid++) {
|
||||||
|
int idcode;
|
||||||
|
const char *libname_def, *name_def;
|
||||||
|
|
||||||
|
if (BLO_library_path_explode(path, libname, &group, &name)) {
|
||||||
|
idcode = BKE_idcode_from_name(group);
|
||||||
|
libname_def = libname;
|
||||||
|
name_def = name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idcode = path_to_idcode(path);
|
||||||
|
libname_def = "";
|
||||||
|
name_def = path;
|
||||||
|
}
|
||||||
|
if (idcode != 0) {
|
||||||
|
WMLinkAppendDataItem *item;
|
||||||
|
|
||||||
|
AssetRef *aref = BKE_libraries_asset_repository_uuid_find(bmain, uuid);
|
||||||
|
ID *old_id = aref ? ((LinkData *)aref->id_list.first)->data : NULL;
|
||||||
|
BLI_assert(!old_id || (old_id->uuid && ASSETUUID_COMPARE(old_id->uuid, uuid)));
|
||||||
|
|
||||||
|
lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname_def));
|
||||||
|
|
||||||
|
BLI_remlink(which_libbase(bmain, GS(old_id->name)), old_id);
|
||||||
|
item = wm_link_append_data_item_add(lapp_data, name_def, idcode, uuid, old_id);
|
||||||
|
BLI_BITMAP_ENABLE(item->libraries, lib_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lib_relocate_do(bmain, scene, NULL, lapp_data, op->reports, auce->ae->type, do_reload);
|
||||||
|
|
||||||
|
wm_link_append_data_free(lapp_data);
|
||||||
|
BLI_ghash_free(libraries, MEM_freeN, NULL);
|
||||||
|
BKE_filedir_entryarr_clear(paths);
|
||||||
|
MEM_freeN(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup. */
|
||||||
|
for (AssetUpdateCheckEngine *auce = engines.first; auce; auce = auce->next) {
|
||||||
|
BKE_asset_engine_free(auce->ae);
|
||||||
|
MEM_SAFE_FREE(auce->uuids.uuids);
|
||||||
|
}
|
||||||
|
BLI_freelistN(&engines);
|
||||||
|
|
||||||
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
||||||
|
G.f &= ~G_ASSETS_NEED_RELOAD;
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WM_OT_assets_reload(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
ot->name = "Reload Assets";
|
||||||
|
ot->idname = "WM_OT_assets_reload";
|
||||||
|
ot->description = "Reload the given assets (either explicitely by their UUIDs, or all curently tagged for reloading)";
|
||||||
|
|
||||||
|
// ot->invoke = wm_assets_reload_invoke;
|
||||||
|
ot->exec = wm_assets_reload_exec;
|
||||||
|
|
||||||
|
ot->flag |= OPTYPE_UNDO; /* XXX Do we want to keep this? Is it even working? */
|
||||||
|
|
||||||
|
prop = RNA_def_collection_runtime(ot->srna, "uuids", &RNA_AssetUUID, "UUIDs", "UUIDs of assets to reload");
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@@ -40,6 +40,9 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "RNA_define.h"
|
||||||
|
#include "RNA_types.h"
|
||||||
|
|
||||||
#include "DNA_genfile.h"
|
#include "DNA_genfile.h"
|
||||||
#include "DNA_scene_types.h"
|
#include "DNA_scene_types.h"
|
||||||
#include "DNA_userdef_types.h"
|
#include "DNA_userdef_types.h"
|
||||||
@@ -54,6 +57,7 @@
|
|||||||
|
|
||||||
#include "BLO_writefile.h"
|
#include "BLO_writefile.h"
|
||||||
|
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_blender.h"
|
#include "BKE_blender.h"
|
||||||
#include "BKE_blender_undo.h"
|
#include "BKE_blender_undo.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
@@ -89,8 +93,6 @@
|
|||||||
#include "GHOST_Path-api.h"
|
#include "GHOST_Path-api.h"
|
||||||
#include "GHOST_C-api.h"
|
#include "GHOST_C-api.h"
|
||||||
|
|
||||||
#include "RNA_define.h"
|
|
||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
#include "WM_types.h"
|
#include "WM_types.h"
|
||||||
|
|
||||||
@@ -501,7 +503,9 @@ void WM_exit_ext(bContext *C, const bool do_python)
|
|||||||
/* render code might still access databases */
|
/* render code might still access databases */
|
||||||
RE_FreeAllRender();
|
RE_FreeAllRender();
|
||||||
RE_engines_exit();
|
RE_engines_exit();
|
||||||
|
|
||||||
|
BKE_asset_engines_exit();
|
||||||
|
|
||||||
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
|
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
|
||||||
|
|
||||||
if (C && wm)
|
if (C && wm)
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "DNA_space_types.h"
|
#include "DNA_space_types.h"
|
||||||
|
|
||||||
|
#include "BKE_screen.h"
|
||||||
|
|
||||||
#include "BLI_rect.h"
|
#include "BLI_rect.h"
|
||||||
#include "BLI_math_base.h"
|
#include "BLI_math_base.h"
|
||||||
|
|
||||||
@@ -60,7 +62,8 @@ void WM_operator_properties_filesel(
|
|||||||
if (flag & WM_FILESEL_FILEPATH)
|
if (flag & WM_FILESEL_FILEPATH)
|
||||||
RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
|
RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
|
||||||
|
|
||||||
if (flag & WM_FILESEL_DIRECTORY)
|
/* Enforce directory in file cases, needed with asset engines. */
|
||||||
|
if (flag & (WM_FILESEL_DIRECTORY | WM_FILESEL_FILEPATH | WM_FILESEL_FILENAME | WM_FILESEL_FILES))
|
||||||
RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Directory of the file");
|
RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Directory of the file");
|
||||||
|
|
||||||
if (flag & WM_FILESEL_FILENAME)
|
if (flag & WM_FILESEL_FILENAME)
|
||||||
@@ -69,6 +72,23 @@ void WM_operator_properties_filesel(
|
|||||||
if (flag & WM_FILESEL_FILES)
|
if (flag & WM_FILESEL_FILES)
|
||||||
RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
|
RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
|
||||||
|
|
||||||
|
if (flag & (WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES)) {
|
||||||
|
prop = RNA_def_string(ot->srna, "asset_engine", NULL, BKE_ST_MAXNAME, "Asset Engine",
|
||||||
|
"Identifier of relevant asset engine (if any)");
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
if (flag & (WM_FILESEL_FILEPATH | WM_FILESEL_FILENAME)) {
|
||||||
|
prop = RNA_def_int_vector(ot->srna, "asset_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Asset UUID", "Identifier of this item in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
prop = RNA_def_int_vector(ot->srna, "variant_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Variant UUID", "Identifier of this item's variant in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
prop = RNA_def_int_vector(ot->srna, "revision_uuid", 4, NULL, INT_MIN, INT_MAX,
|
||||||
|
"Revision UUID", "Identifier of this item's revision in current asset engine", INT_MIN, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (action == FILE_SAVE) {
|
if (action == FILE_SAVE) {
|
||||||
/* note, this is only used to check if we should highlight the filename area red when the
|
/* note, this is only used to check if we should highlight the filename area red when the
|
||||||
* filepath is an existing file. */
|
* filepath is an existing file. */
|
||||||
|
@@ -4124,6 +4124,8 @@ void wm_operatortype_init(void)
|
|||||||
WM_operatortype_append(WM_OT_quit_blender);
|
WM_operatortype_append(WM_OT_quit_blender);
|
||||||
WM_operatortype_append(WM_OT_open_mainfile);
|
WM_operatortype_append(WM_OT_open_mainfile);
|
||||||
WM_operatortype_append(WM_OT_revert_mainfile);
|
WM_operatortype_append(WM_OT_revert_mainfile);
|
||||||
|
WM_operatortype_append(WM_OT_assets_update_check);
|
||||||
|
WM_operatortype_append(WM_OT_assets_reload);
|
||||||
WM_operatortype_append(WM_OT_link);
|
WM_operatortype_append(WM_OT_link);
|
||||||
WM_operatortype_append(WM_OT_append);
|
WM_operatortype_append(WM_OT_append);
|
||||||
WM_operatortype_append(WM_OT_lib_relocate);
|
WM_operatortype_append(WM_OT_lib_relocate);
|
||||||
|
@@ -62,5 +62,8 @@ void WM_OT_append(struct wmOperatorType *ot);
|
|||||||
void WM_OT_lib_relocate(struct wmOperatorType *ot);
|
void WM_OT_lib_relocate(struct wmOperatorType *ot);
|
||||||
void WM_OT_lib_reload(struct wmOperatorType *ot);
|
void WM_OT_lib_reload(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
void WM_OT_assets_update_check(struct wmOperatorType *ot);
|
||||||
|
void WM_OT_assets_reload(struct wmOperatorType *ot);
|
||||||
|
|
||||||
#endif /* __WM_FILES_H__ */
|
#endif /* __WM_FILES_H__ */
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
struct ARegion;
|
struct ARegion;
|
||||||
struct ARegionType;
|
struct ARegionType;
|
||||||
|
struct AssetEngine;
|
||||||
struct BMEditMesh;
|
struct BMEditMesh;
|
||||||
struct Base;
|
struct Base;
|
||||||
struct BoundBox;
|
struct BoundBox;
|
||||||
@@ -379,6 +380,8 @@ void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct
|
|||||||
void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE
|
void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE
|
||||||
void ED_render_engine_changed(struct Main *bmain) RET_NONE
|
void ED_render_engine_changed(struct Main *bmain) RET_NONE
|
||||||
|
|
||||||
|
struct AssetEngine *ED_filelist_assetengine_get(struct SpaceFile *sfile) RET_NULL
|
||||||
|
|
||||||
void ED_file_read_bookmarks(void) RET_NONE
|
void ED_file_read_bookmarks(void) RET_NONE
|
||||||
void ED_file_change_dir(struct bContext *C) RET_NONE
|
void ED_file_change_dir(struct bContext *C) RET_NONE
|
||||||
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE
|
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE
|
||||||
@@ -621,6 +624,9 @@ void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *co
|
|||||||
void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE
|
void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE
|
||||||
void uiTemplateImageStereo3d(struct uiLayout *layout, struct PointerRNA *stereo3d_format_ptr) RET_NONE
|
void uiTemplateImageStereo3d(struct uiLayout *layout, struct PointerRNA *stereo3d_format_ptr) RET_NONE
|
||||||
|
|
||||||
|
/* rna asset */
|
||||||
|
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr) RET_NONE
|
||||||
|
|
||||||
/* rna render */
|
/* rna render */
|
||||||
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) RET_NULL
|
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) RET_NULL
|
||||||
struct RenderResult *RE_AcquireResultRead(struct Render *re) RET_NULL
|
struct RenderResult *RE_AcquireResultRead(struct Render *re) RET_NULL
|
||||||
|
@@ -50,8 +50,11 @@
|
|||||||
#include "BLI_callbacks.h"
|
#include "BLI_callbacks.h"
|
||||||
#include "BLI_string.h"
|
#include "BLI_string.h"
|
||||||
|
|
||||||
|
#include "RNA_define.h"
|
||||||
|
|
||||||
/* mostly init functions */
|
/* mostly init functions */
|
||||||
#include "BKE_appdir.h"
|
#include "BKE_appdir.h"
|
||||||
|
#include "BKE_asset_engine.h"
|
||||||
#include "BKE_blender.h"
|
#include "BKE_blender.h"
|
||||||
#include "BKE_brush.h"
|
#include "BKE_brush.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
@@ -75,8 +78,6 @@
|
|||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
|
|
||||||
#include "RNA_define.h"
|
|
||||||
|
|
||||||
#ifdef WITH_FREESTYLE
|
#ifdef WITH_FREESTYLE
|
||||||
# include "FRS_freestyle.h"
|
# include "FRS_freestyle.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -403,6 +404,7 @@ int main(
|
|||||||
psys_init_rng();
|
psys_init_rng();
|
||||||
/* end second init */
|
/* end second init */
|
||||||
|
|
||||||
|
BKE_asset_engines_init();
|
||||||
|
|
||||||
#if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
|
#if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
|
||||||
G.background = true; /* python module mode ALWAYS runs in background mode (for now) */
|
G.background = true; /* python module mode ALWAYS runs in background mode (for now) */
|
||||||
|
Reference in New Issue
Block a user