Compare commits
2249 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a0f1c4126 | |||
| a792a0e7ea | |||
| cad85c8a7a | |||
| c40d25df29 | |||
| 5d4eab87f8 | |||
| d3ee4b1eda | |||
| b331a3b3fd | |||
| 0ec0b63ad2 | |||
| 659c2184b3 | |||
| 6bbd4defaf | |||
| ea4867d5b1 | |||
| 8d14b4798e | |||
| 1283747b59 | |||
| a2df815ba6 | |||
| cd7d6d470b | |||
| e8ef3c14d4 | |||
| 3a8ca47fce | |||
| 176607db25 | |||
| c389c2f6e4 | |||
| 144de5dd78 | |||
| 139ca8f6ef | |||
| 741602c9cc | |||
| 825561d6f4 | |||
| d932043905 | |||
| 68d613ef0d | |||
| 6ffcddcb87 | |||
| e9ece451af | |||
| 5d8db7fa96 | |||
| 608de9970b | |||
| 97de56756f | |||
| 854f882090 | |||
| 1119c1e68f | |||
| c5bc58ee46 | |||
| 0cd99fc3b3 | |||
| dadec3bd25 | |||
| 6ac1bae539 | |||
| 068076a2c2 | |||
| 51fe856360 | |||
| c719b4f3c3 | |||
| f7f45dc4c8 | |||
| dfbafdc3fb | |||
| 2d62eab4b4 | |||
| 4478c09544 | |||
| 438cdafd60 | |||
| 53b6c1f39a | |||
| 0c540ebea6 | |||
| 269e88b18d | |||
| 9a86def109 | |||
| faa6582adc | |||
| 77bba5e9f9 | |||
| bbfd2fb66c | |||
| ec37f295c7 | |||
| af44f2c720 | |||
| 913a9dcdc3 | |||
| 62b264f770 | |||
| edc2938fb8 | |||
| 2498414e91 | |||
| 3c5929258b | |||
| 810a01b779 | |||
| ad2957d534 | |||
| 6742f54243 | |||
| 5437f43790 | |||
| fc14556d43 | |||
| 4bd4c43d1a | |||
| f27e85eeb0 | |||
| 16a70dd267 | |||
| a53caab12b | |||
| 2cead53fc9 | |||
| 77defa69c6 | |||
| 8c540c8b83 | |||
| 0a415fad36 | |||
| 95bb3d6bb1 | |||
| 3142172cff | |||
| 074a265166 | |||
| ce3943446c | |||
| 6c0c2b4365 | |||
| 2fc8a05aec | |||
| 3eab6c5af2 | |||
| d1bd519e7c | |||
| 0b62184c51 | |||
| 7ae4bc208a | |||
| c28fbe566d | |||
| 5ae8d9b220 | |||
| 4d3ac11467 | |||
| 5777523b35 | |||
| e0eb666f6c | |||
| 19ebe3feb8 | |||
| b9e9480e5c | |||
| 70b7131ae7 | |||
| 7ec2c004a2 | |||
| 7e884e1eb1 | |||
| 7689d48632 | |||
| 514c6c11ae | |||
| e18828bed7 | |||
| 0d52d9aa52 | |||
| bf9db2148c | |||
| 768f7c0e45 | |||
| d160459f4a | |||
| 69b16484ec | |||
| 5f023e1e25 | |||
| b7996a4ad4 | |||
| 447bb98480 | |||
| 68d43a49df | |||
| 3353297858 | |||
| f56e4fe1a4 | |||
| 5a6e6b2733 | |||
| 58b96efe06 | |||
| 0328cfe83e | |||
| 4270fece64 | |||
| 9cba0c0b02 | |||
| 64201d49f0 | |||
| c801fcd835 | |||
| aac9946aef | |||
| ebdddf0bc0 | |||
| a8ac725564 | |||
| 342684587a | |||
| 9a532f2cda | |||
| 909b7fb425 | |||
| 0913c5e167 | |||
| 9abad0063e | |||
| 4b851f9b98 | |||
| a8339496e5 | |||
| 9a183196a2 | |||
| 5a12aa9e1b | |||
| 5c0d62ac2e | |||
| 3d511efbb9 | |||
| 05a159d648 | |||
| 5a9aa812e2 | |||
| 35a9deb301 | |||
| c0ed445918 | |||
| f954ace66b | |||
| 6776f8a79f | |||
| ba345cb823 | |||
| 39abd88a54 | |||
| ecccdf0279 | |||
| 095e4a8799 | |||
| a66ae2f51b | |||
| 781c6449d3 | |||
| eca952b8c5 | |||
| 13d4ee03b3 | |||
| 22f9af6bf3 | |||
| d01c071d25 | |||
| 3f4bf9062c | |||
| 92e0d7bab2 | |||
| d9174a110b | |||
| f9c92b7c78 | |||
| bb87cd5fba | |||
| 5d21c2d300 | |||
| da08a4129e | |||
| bff99dcf73 | |||
| 1d7538a557 | |||
| e483be7726 | |||
| 3b8a34bf25 | |||
| 0f6dfb782e | |||
| c8aada9941 | |||
| 3d4fa72b51 | |||
| 936ffcaabc | |||
| 84721d045e | |||
| 0443c73aab | |||
| 5778d74fbb | |||
| b67faf780e | |||
| 3afbd8f2e1 | |||
| fb771bf797 | |||
| 46f42ba9c8 | |||
| bee41d9491 | |||
| f37fb67e5a | |||
| 940fc985e7 | |||
| 384abca49e | |||
| c04eb822b7 | |||
| 0a51662c0b | |||
| 84af2eb8e1 | |||
| f3ef0fcf57 | |||
| 59f450bcfd | |||
| 53db1d2c9b | |||
| 8cc9b69017 | |||
| 12098fe113 | |||
| 53053d0693 | |||
| 829629d05f | |||
| 49233429e4 | |||
| 47b6dd34af | |||
| 4bd71d676f | |||
| 9a860c355a | |||
| c42a473521 | |||
| 43eb124964 | |||
| 86a8bbee9a | |||
| 4897ea8c35 | |||
| fa2edf8547 | |||
| dcefaf675c | |||
| 82b2558d96 | |||
| 466ecca932 | |||
| 96adde2d52 | |||
| b2a71b505b | |||
| ecafc030ef | |||
| 6007dca4d1 | |||
| 08ecc5005f | |||
| 7b70f2835c | |||
| d8b046a361 | |||
| 9ee683e971 | |||
| 0b01c898f0 | |||
| 08e6ef95ab | |||
| dd89260db3 | |||
| 534a04206b | |||
| 25eaf50586 | |||
| e259a150fb | |||
| 6bc8d6a231 | |||
| 8122846078 | |||
| 8fbdc6a50d | |||
| 2be3ebd401 | |||
| f114bed0d2 | |||
| 31deb4d25d | |||
| 413b776194 | |||
| af18baba7b | |||
| 527695bf53 | |||
| bcd3470b20 | |||
| fd86b347e6 | |||
| 801d72c55a | |||
| 6ea28cb69d | |||
| 19196bede7 | |||
| eed87fc699 | |||
| 6c1a67684e | |||
| e5b6055e7d | |||
| 3ea78d07b1 | |||
| c8c06ff230 | |||
| bbc596ad6c | |||
| 0930828a81 | |||
| 8c71406615 | |||
| 1b01dba827 | |||
| 4aa52ddd60 | |||
| b80de21136 | |||
| ca927e4227 | |||
| f2c17a64fb | |||
| c793624195 | |||
| 42d54163c5 | |||
| 5f2f80f480 | |||
| 88be1fee15 | |||
| 0a6a44522a | |||
| 0ba54b4b7c | |||
| 56b35ef6fb | |||
| 03855be6f9 | |||
| 39b55e20c0 | |||
| 24ab8e0b52 | |||
| a961938716 | |||
| 5c2b9d6011 | |||
| 66def25eab | |||
| 16b7338a59 | |||
| 5b89f42738 | |||
| 882a0bcb7d | |||
| 629d397508 | |||
| 346384f8fc | |||
| fe4af49759 | |||
| 5370236743 | |||
| ee289e4a30 | |||
| 83ccbc7add | |||
| aa633bf2c7 | |||
| 621b92cd5e | |||
| 0d549ae203 | |||
| d944e67a69 | |||
| e2b13be7a0 | |||
| 8750485c6d | |||
| 1f9c1e6627 | |||
| 050e782df5 | |||
| 732f4856c6 | |||
| 27863c0bc9 | |||
| f0215a7009 | |||
| 3a06962045 | |||
| 6fffba5bb2 | |||
| 2ace8e0a5e | |||
| 99e99e5b60 | |||
| fc19e7dfdb | |||
| 2398fa4044 | |||
| aedfb6e6fa | |||
| c760a1c545 | |||
| bcb30ce933 | |||
| a4c3485440 | |||
| e8e223630a | |||
| 7b68bdce5f | |||
| 8884e47051 | |||
| 7c352e2038 | |||
| 2b20d3ef64 | |||
| 0d5a7f3224 | |||
| 4bc0cdd8b3 | |||
| 3511c95836 | |||
| 5456ada1bd | |||
| 1fa3ef37c3 | |||
| a5d8c49d75 | |||
| 0e69125217 | |||
| 046ecb794d | |||
| d61ebcf446 | |||
| cfb3c942d7 | |||
| e49a3275e2 | |||
| 30964aec70 | |||
| 4e39d09d1d | |||
| 162b70ce5d | |||
| 4b49d5d355 | |||
| 3e18a46758 | |||
| d6edc898c5 | |||
| 1dcaf135e5 | |||
| 25919e8393 | |||
| 1080a4e6f9 | |||
| b97769bf5c | |||
| d17c1c57be | |||
| fd1fc0f1d1 | |||
| eeddfcbec2 | |||
| fe2b9bd444 | |||
| 5ebb4b54d9 | |||
| cdd2967087 | |||
| e61505149a | |||
| 8dbe249bf9 | |||
| 38a0857a69 | |||
| 2b1b586251 | |||
| f36cdde500 | |||
| 6de1bfb64c | |||
| a5e82117cb | |||
| 2b7d04368a | |||
| a9dbdbc822 | |||
| 6528829796 | |||
| 3ad682a898 | |||
| 7aca2ee5be | |||
| 1c99f118ff | |||
| b49be74501 | |||
| 55f69da613 | |||
| ae7966a20c | |||
| 2e92fdf272 | |||
| cf9a3cdc38 | |||
| 70951375c9 | |||
| 6329a0070d | |||
| 29fae88610 | |||
| ee0c0fa6ba | |||
| 33822213e6 | |||
| cb05bedf08 | |||
| 4cf328c50b | |||
| f44eb0f8ba | |||
| 76c9029ec3 | |||
| 68e3516075 | |||
| 19ff8e95e5 | |||
| 4bf49bf6a6 | |||
| 0e377e43cc | |||
| f9f23806ed | |||
| 3569e16519 | |||
| 2a40ddd5f9 | |||
| efcd8987d9 | |||
| e66a4ce337 | |||
| 6d19d7c257 | |||
| 988aee863c | |||
| 8253899a70 | |||
| 4edca43531 | |||
| a876fc788d | |||
| cc79e5ca83 | |||
| 8aeb204c8a | |||
| db73939504 | |||
| de90187eb0 | |||
| 8aa809d2bc | |||
| 9e28d91879 | |||
| 2e89516b6e | |||
| f690b8e505 | |||
| 5964e4c332 | |||
| 6033b200e6 | |||
| 0ee33d34f2 | |||
| 44cb99f663 | |||
| 99170bc25b | |||
| 07640b1961 | |||
| e5cb41601e | |||
| f9d8e64a31 | |||
| 7bfdb82225 | |||
| 04aefeae55 | |||
| d6cad30c9f | |||
| 28358306e1 | |||
| 5539a982b5 | |||
| ed22433178 | |||
| 127876bd1b | |||
| c5cae05683 | |||
| 2f3cbdd7c5 | |||
| 9c682e2cc0 | |||
| f31dfd49d9 | |||
| 731b356c95 | |||
| 6d48a01801 | |||
| 3ec06fa3cc | |||
| 5a1d4ad491 | |||
| 581d67177d | |||
| ac6347fece | |||
| ebb42aa419 | |||
| 8223f9742e | |||
| dfdacba649 | |||
| eeeffd1ad1 | |||
| 93fc797b2e | |||
| 094d6de8e0 | |||
| 3d9fc4c40f | |||
| 3cdc207b50 | |||
| 5acd895e0d | |||
| 3715af2172 | |||
| be4d7a6249 | |||
| 04db1ff7cb | |||
| 5f1a04cfa0 | |||
| 4783e22fdc | |||
| db4903cdc4 | |||
| 248e37c292 | |||
| 8a8ba43bde | |||
| 5c0bc4913e | |||
| ca84ed7e63 | |||
| a64fb40d7e | |||
| d11102c643 | |||
| 745b5328eb | |||
| 5fefc74da4 | |||
| a3a73426bf | |||
| 276d867ab2 | |||
| 49b6a1725f | |||
| 4c67f4cc26 | |||
| b369cc4afc | |||
| 52a7f3e2dc | |||
| 85d1048762 | |||
| 8b80c79feb | |||
| 9bef4cb797 | |||
| 39edd3bdcd | |||
| b4585ce13a | |||
| e47790c3f8 | |||
| 5098088237 | |||
| b1c0d614a3 | |||
| 66c9d29539 | |||
| 655c8e609d | |||
| 948a0713d5 | |||
| b43d883db6 | |||
| 73367a10ea | |||
| b9eba042c0 | |||
| 17a33166a4 | |||
| ffbaf87dc9 | |||
| 8ea74c38c3 | |||
| 5789f20794 | |||
| 133e60410c | |||
| 57a8622e9a | |||
| 634039d81a | |||
| b9c9990bdb | |||
| 1e31e737f5 | |||
| 5e3f579431 | |||
| e9e4df8d01 | |||
| a3cdc4fb83 | |||
| c034e5922f | |||
| 3d8d726a52 | |||
| 1b09ac4757 | |||
| f7012d8275 | |||
| e61950267b | |||
| 4c9ff08f4f | |||
| 8668488a20 | |||
| 31f8dc5cbf | |||
| a477129bc1 | |||
| c46b8aecbc | |||
| a010b6177c | |||
| d38b7012e9 | |||
| 6a6152eb0a | |||
| 15121e6d4e | |||
| a8e44d0093 | |||
| fd8f74cf43 | |||
| 472e4da100 | |||
| 607fe8ed4b | |||
| a0a479eb53 | |||
| 04cdb15ceb | |||
| 180e0a3645 | |||
| c931800642 | |||
| e839d1a129 | |||
| 1efec52b33 | |||
| 3799481c35 | |||
| c1025612d1 | |||
| e07a8fbe31 | |||
| 2d52cb1d55 | |||
| a1cdbe5762 | |||
| 2f3bbf1f59 | |||
| 7ceb13d041 | |||
| d04d93eb9b | |||
| f6a3bc9168 | |||
| dca79490da | |||
| abf37168de | |||
| 67fadf0c94 | |||
| 1b29805fc9 | |||
| fcd3bbecdf | |||
| 3d767ffcc7 | |||
| f88711ebf9 | |||
| 17cd564ba6 | |||
| 8bb3bba7e8 | |||
| 5d3dda7a9d | |||
| 5761c182ee | |||
| 0e23e23a7c | |||
| e2736f4db1 | |||
| 1ea78293d0 | |||
| df0a195f38 | |||
| b00d23c46c | |||
| ed4966a3ff | |||
| b03359a3db | |||
| d4e07e981a | |||
| 2d097d0fd7 | |||
| 278b4547f4 | |||
| ee84127892 | |||
| 3724c40afd | |||
| eaada4cf1f | |||
| 033b25de32 | |||
| 32a12d1d6f | |||
| fe27b0e2ba | |||
| 66fcd4c5a2 | |||
| ccdeb6dc0a | |||
| b579262869 | |||
| 11f1dd1623 | |||
| 6a9a25fc54 | |||
| ef47f6cfd2 | |||
| cecd75063e | |||
| 6dad482efa | |||
| 4aae4489b9 | |||
| 1b00dede02 | |||
| 5700075b7a | |||
| 5a461f5bb3 | |||
| a6cbdccadc | |||
| b662a577ea | |||
| 128b1a423f | |||
| 5e41599d13 | |||
| 2cab94f56c | |||
| eedd673d4c | |||
| 25ffde5a42 | |||
| a06134cd6c | |||
| fa57fee9bb | |||
| 404bfdcf30 | |||
| 87d81a6d92 | |||
| 7d41dc1616 | |||
| c1e1502d35 | |||
| 73949712f6 | |||
| 61778974a4 | |||
| c817deb652 | |||
| 802a0117a7 | |||
| 9b2a450133 | |||
| fcfbe920d5 | |||
| b57331f450 | |||
| 944a61100b | |||
| f8ae1a9997 | |||
| 8ea015aaab | |||
| e38019d74e | |||
| 7da892b49a | |||
| 60c84abfe4 | |||
| efa1ac3807 | |||
| f6b7ab7994 | |||
| c0b6d159fc | |||
| fa85685baa | |||
| d1883bdd9d | |||
| b4ff4df808 | |||
| 3254bfa619 | |||
| bf26cf175f | |||
| 2c287965fc | |||
| 4551ded37e | |||
| b4d05af28f | |||
| eac742e3db | |||
| 57a1201b11 | |||
| 85a8a71fc5 | |||
| bd6bb510f8 | |||
| 0cf8221e62 | |||
| 36d4e8fa62 | |||
| a384290356 | |||
| 8b9226d820 | |||
| 35e639c599 | |||
| 3a7f5fcf03 | |||
| 881cbd6d2f | |||
| b319b710df | |||
| dd1ad34cea | |||
| 9406893722 | |||
| cea4d89697 | |||
| 7bbd31fa2a | |||
| c6d9a04dba | |||
| 77fc1aecb2 | |||
| 24da541747 | |||
| 02f7e9c800 | |||
| cbbc2f42e8 | |||
| 7e73dad7b0 | |||
| bc67fc338e | |||
| 6054e7be0a | |||
| a7f31c59a8 | |||
| 345e97f296 | |||
| 7716d4592d | |||
| 7e4eba9eed | |||
| a1089c9dd6 | |||
| 9a032e7422 | |||
| 55dddb69f7 | |||
| 580d42a63e | |||
| 1a1416aaa4 | |||
| 1d74450216 | |||
| 446a0a174e | |||
| 6405273059 | |||
| bbd0a41191 | |||
| 7bc9003fb8 | |||
| 7c745cd9c6 | |||
| 202f7f9107 | |||
| 1e1fbb4ccf | |||
| 0b17e5d288 | |||
| 3b046c409b | |||
| 9eeb56fe3e | |||
| 3124f8133a | |||
| f99ca77461 | |||
| 0bc1c08d4f | |||
| 3fcf44ae32 | |||
| 4d1dc14b45 | |||
| e4710f54f8 | |||
| ce983ec34a | |||
| bf9b535f66 | |||
| a2f0110f3d | |||
| 367924e669 | |||
| 9c6998c6bc | |||
| 1bf848e418 | |||
| d62e474850 | |||
| 7546333fbc | |||
| 405bb0ad90 | |||
| b7e9f8ce1e | |||
| 00a2da7d18 | |||
| 86c29e23df | |||
| 8765d96c4b | |||
| ee6233b893 | |||
| cebdb43234 | |||
| f65da3d98f | |||
| e6e13b2609 | |||
| 96774bb98c | |||
| 681301ab9b | |||
| 0d68dfcbc1 | |||
| 0a17e9a236 | |||
| 8597d2c681 | |||
| eca53baf6f | |||
| b7bc4ea43e | |||
| 6ab2f35f74 | |||
| c015153e21 | |||
| 7a74418c39 | |||
| 6033b3599e | |||
| 37d98063f0 | |||
| 7fe85b44f9 | |||
| 68125a7f50 | |||
| 166879a1c8 | |||
| b518569674 | |||
| 6a25e05e3c | |||
| 179862b10a | |||
| 339cf51c0c | |||
| c8d06997f5 | |||
| 57979f3c9b | |||
| e70a0e4e0e | |||
| 6268fe957a | |||
| 49ce5eecdf | |||
| 4e1da2b6d0 | |||
| 3f7d24bccf | |||
| de0c051e51 | |||
| 1ef99e657f | |||
| 7cbe1c0a44 | |||
| 8c45f18409 | |||
| ae3c02abae | |||
| 543d4af682 | |||
| 19c49fa82b | |||
| a723b8de7a | |||
| 21c3926714 | |||
| 3d79bf82f4 | |||
| 6338f88db1 | |||
| fdfe60dd09 | |||
| cdff2d0d41 | |||
| eb290bf362 | |||
| 18618deea3 | |||
| 67b64f5ec6 | |||
| f394f2c57f | |||
| 46670c7eeb | |||
| eefc79b5b2 | |||
| 744dd4893d | |||
| 7eed86de38 | |||
| 1c04f5a03c | |||
| 9d9d74faad | |||
| c2342776e1 | |||
| 09aa89f3f9 | |||
| a8430e09f5 | |||
| 768b039cde | |||
| 3f1b9a6b4a | |||
| 638e29b5d6 | |||
| 5abc48269b | |||
| c81b17c1cb | |||
| c928bc8ce3 | |||
| f33a4975ef | |||
| 5920137968 | |||
| f636e1d45f | |||
| 7e6a243df9 | |||
| ad7ba8f029 | |||
| 3096a26b59 | |||
| ff2a719bf7 | |||
| b6c4aaac8e | |||
| f7ad4ca025 | |||
| 4666b7fb69 | |||
| 125ce48525 | |||
| 114d12b060 | |||
| bf1566884c | |||
| fa7b6a8cec | |||
| 9855104120 | |||
| 36f7125513 | |||
| 6ebd5ddc53 | |||
| 2bc4103ea9 | |||
| 01eab7dccb | |||
| a95dee3d09 | |||
| 891c85a2c1 | |||
| 386f9b2074 | |||
| 325d5a6bcd | |||
| f05d7f4176 | |||
| a8ea2e05a4 | |||
| 8bcb88d6fd | |||
| f9bd431d56 | |||
| 0c6e180937 | |||
| 2c5fcd7d2c | |||
| 1a19c761ae | |||
| 71b8823625 | |||
| 24cab0eabd | |||
| 3e5c236942 | |||
| a3f74b2f68 | |||
| 2d09237bd7 | |||
| d26b94db61 | |||
| 017c41bc5f | |||
| d7857dd026 | |||
| 7ac5a172fa | |||
| f44a64a705 | |||
| 490b630e2d | |||
| 1265dc6334 | |||
| 69f994e1b2 | |||
| 0f841f194f | |||
| db6aecda47 | |||
| 83ca78a5fb | |||
| 2f0ae47c8e | |||
| 11a2d81738 | |||
| bb4ea2db67 | |||
| 70a2321cc1 | |||
| 2331742384 | |||
| d41ea73765 | |||
| 5a5616f258 | |||
| bd3108a40c | |||
| 8c9a12e3a1 | |||
| fe45fa81fc | |||
| 3e30600f70 | |||
| 5c05ec5b98 | |||
| 7024117709 | |||
| fd38b708fb | |||
| 153020283c | |||
| b41d1e0eaf | |||
| fcbfd00b98 | |||
| 51edb08796 | |||
| bb087fdc45 | |||
| a4a2196cc2 | |||
| 8ab96afd5b | |||
| f5b230a2ef | |||
| 076defb0a5 | |||
| 76660ff15b | |||
| 60471ecc1e | |||
| 9e68ba1ea3 | |||
| 414dddbf59 | |||
| a0c61484d2 | |||
| 7f6787c8b8 | |||
| 8c74dcde28 | |||
| 27332a8a17 | |||
| 8733da346b | |||
| e644f5be05 | |||
| 7007601655 | |||
| b1fc1cd11e | |||
| 919edcf1e1 | |||
| d99260c614 | |||
| cf9d1ba541 | |||
| d6628419c9 | |||
| 75eb5491d5 | |||
| c32d8f38ed | |||
| 9f22c35519 | |||
| f775500932 | |||
| fdbdb76c39 | |||
| af26e17fa7 | |||
| 769bf51359 | |||
| c81c316a46 | |||
| e5192ceddd | |||
| 89ddf97fa0 | |||
| 79b2eb0ff7 | |||
| 0ab0c7b8ed | |||
| 1d582a515c | |||
| a4a6064316 | |||
| 910d95a7b6 | |||
| 3cedadd738 | |||
| 3ba2d4428b | |||
| 7a545df299 | |||
| 2b3d6075e2 | |||
| 1073a524b9 | |||
| 6dd9cb6fb8 | |||
| 6789755b06 | |||
| e7dae3a9c1 | |||
| 1f78a15db2 | |||
| 79a4f42ef9 | |||
| 8fdf3799a2 | |||
| 4b095ab61f | |||
| 757d617ef3 | |||
| 17923c0d9e | |||
| c9f9db9069 | |||
| 90d03c784c | |||
| ea436444f2 | |||
| 209bb4290f | |||
| 7d9d2e508d | |||
| 5bd8e7d4e8 | |||
| 30f19be555 | |||
| 3e140ddcfe | |||
| 81143324a5 | |||
| fabb646a0b | |||
| 85131e359e | |||
| 5a0f8019c7 | |||
| f067dc8b32 | |||
| 14110cdea8 | |||
| f885296fb2 | |||
| a6c5f46f2d | |||
| 145ea35ac3 | |||
| 1399ed198c | |||
| c2fb99ce49 | |||
| 53542a9d37 | |||
| e77690c268 | |||
| d8e45ef866 | |||
| ffc24ad518 | |||
| b79c17b43c | |||
| be415dab1d | |||
| d0278dad15 | |||
| 927ff2bca7 | |||
| fc7b9029c9 | |||
| 187b529dbb | |||
| 2061947138 | |||
| 04c24cb686 | |||
| f38935459b | |||
| a6ce907a4f | |||
| f1dbfffd82 | |||
| a46d344db2 | |||
| 5476a03799 | |||
| d4569d66ac | |||
| c4ce6d9ab1 | |||
| fa083142a7 | |||
| 8aa8451434 | |||
| a1f81bbe97 | |||
| e9669c6594 | |||
| 690e7144c1 | |||
| a53b3d496c | |||
| be7f436951 | |||
| 7708753ed3 | |||
| 95d5ab706a | |||
| 7afb4e68f1 | |||
| 4caad33c9a | |||
| 1ece12b907 | |||
| 88c2f8504e | |||
| 9137a9ec80 | |||
| fad35e7e00 | |||
| 009925724e | |||
| 8504f30594 | |||
| 96116659be | |||
| 1e7df3606a | |||
| 603029b106 | |||
| 4ca54b2f1d | |||
| 555e24dc59 | |||
| a651aaea00 | |||
| 258b804941 | |||
| dbb4e67737 | |||
| ec1a5d1318 | |||
| cdab6cfdbe | |||
| 33b3d5edfb | |||
| e1aa6f7e84 | |||
| bfc1665d87 | |||
| 9e937f8113 | |||
| d114d9e386 | |||
| 4e8d1366b6 | |||
| 8afb0255f0 | |||
| dac6c662c5 | |||
| 577229bb6e | |||
| b5fdf4f1da | |||
| bf7d383066 | |||
| 6e977b668c | |||
| fdc52d933a | |||
| 316f7309a1 | |||
| ff75a28080 | |||
| e7b5e816d0 | |||
| db41bc2870 | |||
| 585aeb7f91 | |||
| 1b644a164e | |||
| c4e42f46a9 | |||
| bff4d1239c | |||
| 8a89e160ed | |||
| 198052358e | |||
| 6730b7d656 | |||
| f917efd430 | |||
| 7d51fc7dfb | |||
| b192495bbc | |||
| 34a697fc37 | |||
| 2dda514cb0 | |||
| 82d667e30c | |||
| 29b0b9cfcd | |||
| ed7f92ebc7 | |||
| 93ae8f4066 | |||
| 6b030ac9be | |||
| 8470c44bb0 | |||
| 4c75540ca2 | |||
| 70f43b0003 | |||
| 91452f3b58 | |||
| daeb396fd8 | |||
| ad649d9670 | |||
| 0038722d0f | |||
| 6a00664b2a | |||
| 2956543d27 | |||
| 0fcf722af4 | |||
| ceebdbfdd3 | |||
| 1b05af7f8e | |||
| 123b7b5537 | |||
| 5fa1257e2c | |||
| 5c405a6f40 | |||
| 03b5d6125b | |||
| 2376811df8 | |||
| c48997608d | |||
| 8a5285db41 | |||
| c4d6fc943a | |||
| 3655df08ea | |||
| 7858e6aa7c | |||
| c909988aa5 | |||
| 5deaba9669 | |||
| f162b6662b | |||
| 2d5f342ee8 | |||
| 85a2aee79c | |||
| a4cc671c22 | |||
| 2912138ef2 | |||
| cdae489afa | |||
| 51ad0c18ff | |||
| 998255fb1b | |||
| edfb5811cf | |||
| c733b32672 | |||
| 38862c1a09 | |||
| 03161c81df | |||
| 264c73747a | |||
| 5e53e410ce | |||
| b42ec57f6f | |||
| 4d0f664f50 | |||
| 2ea3b8b068 | |||
| 0810492a2c | |||
| c5178979ce | |||
| 08bdaf07be | |||
| 832764aa3a | |||
| 43c87d0cb6 | |||
| 6a6b944c00 | |||
| 90eb83dcb2 | |||
| 31b722f9d3 | |||
| e3351a9686 | |||
| 19dea9095e | |||
| 3b023da602 | |||
| 33d0a72fce | |||
| 5136fc535f | |||
| 16a21ade8f | |||
| ec2b2dc291 | |||
| 2703a5aebd | |||
| 4bdd21b281 | |||
| 499d41206e | |||
| ece008e790 | |||
| d1cfa88bc0 | |||
| 0e28b55184 | |||
| afccbbe04d | |||
| a4cec09781 | |||
| 54d70ec738 | |||
| 39c3a38e2d | |||
| 699897ddf8 | |||
| 00d3af4816 | |||
| ceadbbcdc1 | |||
| e703b53b3a | |||
| f037cc3c74 | |||
| 7dec942ef7 | |||
| 1d0ca22572 | |||
| a6decc3cc7 | |||
| b58cc107e6 | |||
| a593306a06 | |||
| 0177590699 | |||
| 787fe28fd0 | |||
| 541568e09f | |||
| 5dd7ef6895 | |||
| 153df79699 | |||
| 4ad9af71f5 | |||
| d76671a601 | |||
| ea094a4fbc | |||
| cb11dad4de | |||
| 817cf192c8 | |||
| aec00ab96f | |||
| 48b288cdc2 | |||
| 66d257f620 | |||
| dd14218c34 | |||
| 918231795b | |||
| 9f71172437 | |||
| 69e3b23960 | |||
| 7b426e8103 | |||
| 27e1043fc4 | |||
| 76518712c4 | |||
| 64843d6b0a | |||
| 87fa661591 | |||
| 2ec6d22131 | |||
| f6ac92dc39 | |||
| be69f7ad20 | |||
| 9a7cc494f7 | |||
| 8c3d4d4eda | |||
| 636ca7a74b | |||
| c57c1e94d1 | |||
| 1e1c2cbb7d | |||
| 5399b6f438 | |||
| 41b6c8434a | |||
| 3031b9e6a5 | |||
| 0d5331df59 | |||
| bca75d4930 | |||
| a70965eb6d | |||
| ad21bfda4d | |||
| fef46ffacf | |||
| f803745fc6 | |||
| c36ab1c6ed | |||
| 28f9d7f28f | |||
| 5b225186c4 | |||
| 09bb2a6054 | |||
| e1ea1237b7 | |||
| fb65f5d1ae | |||
| ff439ecd7f | |||
| 4cc4df87ff | |||
| 56aabe20bc | |||
| 4b624381e0 | |||
| c5508f34b3 | |||
| 3c667d7652 | |||
| 4664427784 | |||
| c747ffef95 | |||
| b5b1777304 | |||
| 228004b472 | |||
| a1f91c08ad | |||
| 96dc27d9e6 | |||
| 11f9f15199 | |||
| 991a92429e | |||
| 4f17dc0716 | |||
| 37c7fa9fb4 | |||
| fd2f700390 | |||
| 97255b2b7f | |||
| 8d32141b8f | |||
| 7700779e2c | |||
| 1cc9d2ce5a | |||
| b9980df1b7 | |||
| af8b256a00 | |||
| 324c39931c | |||
| 113325673f | |||
| 857b02706e | |||
| 1e0f1b39b0 | |||
| 6a429facb6 | |||
| 8663a6c7a0 | |||
| b6ec124ceb | |||
| 85a3b72c71 | |||
| d9b489d471 | |||
| 3289c6c305 | |||
| ec83adde3f | |||
| 206c8e1189 | |||
| 07545ba49c | |||
| 8312497d6c | |||
| eed2bed0bd | |||
| 49045cf08c | |||
| 55f7a99d1b | |||
| 98addf78b4 | |||
| 4b42ec3218 | |||
| e469d9d1f9 | |||
| d53d9d88fb | |||
| ed484deec6 | |||
| df9502dd06 | |||
| 6001254160 | |||
| 2b0c4ba215 | |||
| 1e9088f7d2 | |||
| ec9e283d34 | |||
| 20e7d431a6 | |||
| 6c745e6e9b | |||
| d1635e17f6 | |||
| f9e5881b45 | |||
| 869505a659 | |||
| 895d265603 | |||
| e5e60c6bed | |||
| 568e6c8093 | |||
| cf01f1a264 | |||
| be7de02a1d | |||
| b8d88f0dc5 | |||
| 698bc0cdac | |||
| 48a7a863ae | |||
| f2c4fa2b46 | |||
| f996d6cc7a | |||
| 0dbf3ef30a | |||
| 76b558c831 | |||
| c10bb66b12 | |||
| 89a391d001 | |||
| 0fef63956f | |||
| 63c2af4fa4 | |||
| 3ff7ddbea7 | |||
| 21733e7bda | |||
| 3fa60aaed8 | |||
| 9422e37c45 | |||
| c074c8c9d4 | |||
| 27c4956046 | |||
| ebbd7c48d3 | |||
| 079edee146 | |||
| 87f9452bbe | |||
| 9c0c64e87b | |||
| 3b65c120e8 | |||
| 3289835b53 | |||
| 7745d37d6c | |||
| 37e440b093 | |||
| 7792364e8c | |||
| 3a4ad03492 | |||
| cac7dbc607 | |||
| 7326c9cb73 | |||
| beb8e76bb4 | |||
| 43e37caf46 | |||
| a985798a86 | |||
| d09cca948f | |||
| 3f52031b86 | |||
| 7448116f37 | |||
| 4e0d54fe21 | |||
| 10d8275962 | |||
| 157cbc2f68 | |||
| 7d64d2e92a | |||
| f86261c812 | |||
| e1eb33a320 | |||
| cadcc20ea6 | |||
| 56ad7642c9 | |||
| d1695d3408 | |||
| b51fbe5c50 | |||
| 04c0ba65d2 | |||
| c2f5e7d88c | |||
| f456a92f08 | |||
| 48419d8fd9 | |||
| 0ef5dbac4a | |||
| 8014e0d993 | |||
| 739238659e | |||
| 6de593c771 | |||
| 4e9fd3ee9d | |||
| 900056be44 | |||
| 221cb6d5b2 | |||
| 83e693c78a | |||
| 8db5848e91 | |||
| 27807f02c5 | |||
| 30e31ff164 | |||
| ee0fe85cd0 | |||
| b2270b2f4f | |||
| 141252b73f | |||
| 7c4ac2e3a4 | |||
| 46b731b2d3 | |||
| bd76e47976 | |||
| bd2c878b35 | |||
| 84ee9591d1 | |||
| 15b27fa35f | |||
| e41536484b | |||
| d3004fc833 | |||
| 395c5fc922 | |||
| c20de314cc | |||
| 4881e6477f | |||
| 93609837dd | |||
| a8b3c20e66 | |||
| db2fba1faa | |||
| bf9cbb4491 | |||
| 18f32cfbd6 | |||
| a5a3ef17b8 | |||
| 326b827cc6 | |||
| 961efac8e2 | |||
| 418d26d250 | |||
| 07fb2a3e93 | |||
| 5006cca67b | |||
| 735e3b71d6 | |||
| d9da8228d4 | |||
| b5a7e66134 | |||
| 00bc96a2b7 | |||
| 5dd66771fb | |||
| 6f19a7deac | |||
| 811585b00f | |||
| f610377363 | |||
| 8c549a28df | |||
| cab22ffeac | |||
| 60c9f576f6 | |||
| b619c2069f | |||
| 3efdcb95cd | |||
| 4b11862ecc | |||
| c5e9b187ae | |||
| 04fc574229 | |||
| f6b6665fed | |||
| 0da9086397 | |||
| c5852c1237 | |||
| 5bbd7cb013 | |||
| a3b4a09fd2 | |||
| bf783c42bd | |||
| 57e832dc65 | |||
| ab2d301968 | |||
| f1f961a43e | |||
| 8e345bd09c | |||
| 0996c307ac | |||
| fb8e505590 | |||
| ec2804a78a | |||
| 29d2ee3273 | |||
| 6e3e6a1944 | |||
| 1005fd2872 | |||
| ab666cc267 | |||
| e79df21353 | |||
| ff0ddbcac0 | |||
| d1604137cc | |||
| 969efff611 | |||
| 293f7cca28 | |||
| 45a48cfcb2 | |||
| 822cc6a781 | |||
| 658f02a6b9 | |||
| 8d675d9bc0 | |||
| fdf135d877 | |||
| a2bb144556 | |||
| c867ed9de4 | |||
| 39ef596bdc | |||
| a9bcaa1493 | |||
| f05163fbeb | |||
| 7ad3e0c544 | |||
| 24882a9324 | |||
| 9bb6ead2b1 | |||
| d6bcbc5cdf | |||
| dc4b261c68 | |||
| 9262f13eef | |||
| 82998d0cc0 | |||
| 8949cfe584 | |||
| c10d1fe279 | |||
| 9ed5ee8310 | |||
| 7b266ef475 | |||
| 09f1a4fbb8 | |||
| c7f55381a5 | |||
| 81f35ffe73 | |||
| 597b362603 | |||
| 0163e4b4e4 | |||
| 98a77ee649 | |||
| c9edd2c8de | |||
| 379ad3a8e7 | |||
| aca64b5dda | |||
| d34639b79b | |||
| 0d4b157207 | |||
| 58160d9624 | |||
| 57e34dfb3c | |||
| 67ab19289d | |||
| 7718bf6858 | |||
| ee467d0203 | |||
| 9b7265810b | |||
| 24dc1092b1 | |||
| ab953f1381 | |||
| 83174e996e | |||
| 38069048fd | |||
| 9fda651595 | |||
| cb13ae57bc | |||
| 6a45d30715 | |||
| a43f24617d | |||
| f11a148d2d | |||
| 73cf4c0e49 | |||
| 8ea3cd1cb5 | |||
| 62979ae06d | |||
| 5e998288d6 | |||
| e01b851e1c | |||
| 2e6a40be96 | |||
| 02c1ec5efc | |||
| 78a6ba31d8 | |||
| 1ae23df0ba | |||
| 36ba9a7309 | |||
| 7ee129b21a | |||
| b3d4123007 | |||
| 5bfd330692 | |||
| 49125d1a7d | |||
| 6050ef41a9 | |||
| 0d809688ee | |||
| da20e80de6 | |||
| 1f46bf2e28 | |||
| f345dbe7e4 | |||
| 490c8d856e | |||
| 897a5b8de6 | |||
| 155cb4f158 | |||
| 445cf5860a | |||
| 6cb1bae032 | |||
| c0c9d667cd | |||
| b946032f56 | |||
| df8826240f | |||
| 5dda4f95a6 | |||
| f3822e6ffa | |||
| 084ad26b73 | |||
| fafecb491e | |||
| 0e6a590305 | |||
| 0e8c9fda5e | |||
| d2ac283570 | |||
| 69bdc16751 | |||
| b8325a38a1 | |||
| 403a1a7e1f | |||
| cf481d2fc4 | |||
| c3e3fc4dba | |||
| 254ad1b26b | |||
| 2c642afd04 | |||
| e43fab7c01 | |||
| 55f2914163 | |||
| 96d7ac7c6a | |||
| c9be096e88 | |||
| e18b8642c4 | |||
| dad83c9004 | |||
| f0a86c360c | |||
| c6444b7d05 | |||
| 6b81b6931f | |||
| b391fb3faf | |||
| 2649c38bf7 | |||
| 81266f2f71 | |||
| 05189f9ff5 | |||
| a3f8783dca | |||
| c20d23a552 | |||
| d2ed926077 | |||
| c0b3ad8253 | |||
| 30495f780a | |||
| a2114c44ad | |||
| 0f06a927ff | |||
| c5c41b8ab5 | |||
| 1f4ca54938 | |||
| 720e3e9272 | |||
| a42400272d | |||
| 19558b48c1 | |||
| 744d875838 | |||
| 59d2523c49 | |||
| 13fdde5e5d | |||
| 86e73c1bae | |||
| 6cd558fd5c | |||
| 8f45c7d27e | |||
| 3518b18351 | |||
| 6dea106650 | |||
| 123a29d126 | |||
| 9a8383de24 | |||
| 2453201d7b | |||
| 14deef3adf | |||
| 8c191e5ba8 | |||
| 20fc4a2efe | |||
| 49a577dd59 | |||
| 8b8f5d45c9 | |||
| cec687bad2 | |||
| 9891e2d986 | |||
| 24b23e2383 | |||
| 413aa106a2 | |||
| 097dcd724f | |||
| 1454880fb7 | |||
| c6a712dec3 | |||
| 2c888b86f5 | |||
| 7481dcf520 | |||
| 435a34cd60 | |||
| 23ffcf8f89 | |||
| 89d6a09401 | |||
| b8fce6a8e1 | |||
| 523e7eb397 | |||
| 30a3668779 | |||
| d95ea479c4 | |||
| baf18a6379 | |||
| 92831ee7d4 | |||
| de823996b5 | |||
| 936974f12c | |||
| 0c88507dcf | |||
| 9184095b34 | |||
| f1eea58b6b | |||
| 49f2206ef0 | |||
| 8f94a14063 | |||
| 9843e0c436 | |||
| e3149cd2b0 | |||
| 7c5d2ab029 | |||
| 6422be116b | |||
| 50eef193ff | |||
| 8092d98ea3 | |||
| ed42891509 | |||
| 6124226428 | |||
| 6c22590d4a | |||
| 950d9ae23a | |||
| a12ff75fee | |||
| 681413bb97 | |||
| 1ebe2c8728 | |||
| 41dd21ac7b | |||
| 6b6d9706bd | |||
| 1b57a79636 | |||
| a1f3b7d53f | |||
| 1118ef8f19 | |||
| 4b9526adb1 | |||
| ef3f42dfab | |||
| 6f018668c2 | |||
| f20d6e8d05 | |||
| 0574bf8aba | |||
| 7ea9f8ddcc | |||
| e4d9cb77fc | |||
| 7eee33a6a0 | |||
| 3bbafe14f5 | |||
| 1dc048662b | |||
| 7546651a30 | |||
| 6d16131b03 | |||
| 7eb196b4d1 | |||
| 1e8f7f7ba8 | |||
| eefbd1610e | |||
| 0f8af51da6 | |||
| c14dad91b2 | |||
| 2538262531 | |||
| 453a135a3e | |||
| 0cfa6d8097 | |||
| 7e77f3b902 | |||
| 71d2467963 | |||
| a6140c799d | |||
| bd7217b090 | |||
| cc45f4f212 | |||
| d95710f8e0 | |||
| b3703f1f91 | |||
| 104d63fd7c | |||
| df994764a5 | |||
| 764ef2dcc9 | |||
| 1dddc22a9b | |||
| ebac5c4a70 | |||
| 59a3715e40 | |||
| 86bb2f325e | |||
| eb370afe4a | |||
| fc06b1762f | |||
| a1fed86b28 | |||
| a96a265a7b | |||
| a2d65bb523 | |||
| 7c966fa775 | |||
| 8042d6f892 | |||
| d4c8c0bb52 | |||
| 148d567aa4 | |||
| 85e96c92ed | |||
| b25e440ba9 | |||
| c4d874cdb1 | |||
| 4e96cc4bbb | |||
| 78f928544f | |||
| 0edbe77903 | |||
| ccf8c3bd83 | |||
| f8020f4728 | |||
| 23bded5697 | |||
| 9df7292af6 | |||
| bcb05fbc14 | |||
| 7adc495692 | |||
| 69f8ee8ee2 | |||
| 4acb97e02e | |||
| 7cd840bf83 | |||
| 9577736788 | |||
| f7ec499ee9 | |||
| a64e1b3397 | |||
| abeba63ed5 | |||
| 0dd05887d2 | |||
| f8b3873b83 | |||
| 63362c97f5 | |||
| b07b214293 | |||
| e368ae3230 | |||
| 9cf627a656 | |||
| 5d383f1885 | |||
| f9b7ede7ff | |||
| a2a44bb7ef | |||
| 1f37ca437b | |||
| ac77e047f4 | |||
| 02a6baad8a | |||
| 799ef3bc0d | |||
| b337dccd0c | |||
| 8867bf262b | |||
| 0543670734 | |||
| 9c66afb6fe | |||
| 0dc8241605 | |||
| 7ca5c4099e | |||
| e40c8fa164 | |||
| df88d0cbea | |||
| f73e785662 | |||
| 1bb685cc57 | |||
| 5d4da5ede9 | |||
| fe295788e7 | |||
| f8b3eaedb5 | |||
| e5e83eba05 | |||
| 28a35c9883 | |||
| d8a6c7c1bf | |||
| c8f6806287 | |||
| 8bf57814a4 | |||
| c2d4338024 | |||
| 6410862b15 | |||
| 4845668a4a | |||
| 146adbf831 | |||
| d1f291acb8 | |||
| 4b7c3010e0 | |||
| 4039f66530 | |||
| 4ce6362f4c | |||
| 5765ebef08 | |||
| a3eb501225 | |||
| 82706bf152 | |||
| 5e852ba1fd | |||
| d49cdb2ded | |||
| a8ad1f8097 | |||
| 2ea3c4acac | |||
| d1e3bad24f | |||
| 06f46e4b14 | |||
| 54714fd989 | |||
| 912d308b9d | |||
| 0b71e4a98a | |||
| 900bef9ccf | |||
| 7106d1e605 | |||
| 6840ec0d09 | |||
| 0e8e811b14 | |||
| 3dc986bbf6 | |||
| 34813dc07c | |||
| f79d75076c | |||
| 57b5ce84a5 | |||
| 395338f46a | |||
| c33cd27626 | |||
| 2ca4512443 | |||
| 76b4dc7346 | |||
| 53609d2ecd | |||
| d24054ac00 | |||
| 2c0619f69d | |||
| f039aeb4c8 | |||
| ab0e47d402 | |||
| 03128b7530 | |||
| ed3e79325f | |||
| c4c715fcd0 | |||
| 86b83ddbc9 | |||
| 62c43eaf53 | |||
| 33cf2243a8 | |||
| 02a1c2f096 | |||
| b841150c23 | |||
| 3db19ba2eb | |||
| 22d1f50455 | |||
| baee140518 | |||
| deaa4529ae | |||
| bed29749f2 | |||
| e57cbd3348 | |||
| 2f788445a9 | |||
| d4e55c69c1 | |||
| d07351c8ba | |||
| 2412caf494 | |||
| 9b6f75afd3 | |||
| a4b2a6537c | |||
| cfaa7d9e54 | |||
| 0ca3012c67 | |||
| 42ebece808 | |||
| 0d7510c129 | |||
| ebe697f62a | |||
| 29240fd14b | |||
| 97f4d18a13 | |||
| 8ef0dd69da | |||
| 30d41b33d1 | |||
| 2ce06cfe08 | |||
| 3b1a1125d2 | |||
| 93cdfb566b | |||
| b61ac2069d | |||
| 6e8a71ec34 | |||
| 3b3fc0151e | |||
| f5643f2332 | |||
| 38e5d961f6 | |||
| 5be15bed82 | |||
| deb6aa8cc5 | |||
| 3b3e19ee8a | |||
| a713e47713 | |||
| abbc83bd51 | |||
| 7d4aaa8cdb | |||
| 06b3172333 | |||
| 2062cf8fe4 | |||
| 3e15da5bcc | |||
| 520eace689 | |||
| 9ed3c5dc46 | |||
| 7db3834f0b | |||
| 5979b1a1b6 | |||
| d283a8c878 | |||
| 3f2a258930 | |||
| 550d36dc33 | |||
| 46b9d9e359 | |||
| 3e084a3b0e | |||
| 391a663360 | |||
| 068ae2f344 | |||
| 64dfea78b8 | |||
| 3bbcd30396 | |||
| 09bfd3311c | |||
| fdd0e02c35 | |||
| 10b5322b87 | |||
| f01feef636 | |||
| 1aed2b3114 | |||
| adc9b70d72 | |||
| 5f86a70891 | |||
| ea9a84b748 | |||
| c73ca9a6da | |||
| e467e58857 | |||
| bb73777a4a | |||
| a63a62f827 | |||
| 1c6574e69d | |||
| 313785b421 | |||
| b6261f3d80 | |||
| 3dc4de85b5 | |||
| bb0711eb3f | |||
| 0cb647ee1e | |||
| 5a0c37e2b9 | |||
| 4a3ddd5b2c | |||
| e6095e6fd8 | |||
| 33d1d0f8e4 | |||
| d02025b0ed | |||
| 28af99d95d | |||
| 619c8e689a | |||
| c03355d67f | |||
| 417572f3c5 | |||
| c5ed76f104 | |||
| 5721a279c8 | |||
| 0cf8553b2e | |||
| 6d5b865741 | |||
| 7b08e81991 | |||
| 6d4e0ff665 | |||
| bd6ea96ed6 | |||
| 9feccc625b | |||
| 65949662f6 | |||
| 22defb9ad4 | |||
| 37cb4d00df | |||
| a48c0ece4b | |||
| b8c77dc417 | |||
| ed42ae5a79 | |||
| 20f83297ce | |||
| 896dc0fcf6 | |||
| f8a238e670 | |||
| 3b8f2a551b | |||
| 2263633df8 | |||
| 59b7a8ff8f | |||
| 9e6b63e3da | |||
| 5eb63c42f1 | |||
| 1bba1c5ee0 | |||
| f7047d3cfa | |||
| cb16951519 | |||
| 14dc5709ee | |||
| 7d03b0af33 | |||
| 33f7d83c71 | |||
| e469a6b3d8 | |||
| 2971ea6564 | |||
| 02ced9a339 | |||
| 1960a8768e | |||
| f4c8abb1b4 | |||
| ab9630b825 | |||
| e79d6ae971 | |||
| 0348e13258 | |||
| 40c7c7dae8 | |||
| 396695c866 | |||
| a07ae76bcc | |||
| 0221700226 | |||
| d8f3424554 | |||
| 623234c7c2 | |||
| 49aff4eba3 | |||
| 9281d15c70 | |||
| e482826ac3 | |||
| 49e2e292dd | |||
| d721f176f8 | |||
| 58532cd8c5 | |||
| 37fe3ca01a | |||
| 1a01535313 | |||
| 2ba0f5d807 | |||
| 48fa8fd20b | |||
| eeb179fc9a | |||
| 76d1abb9ca | |||
| 68d2aed8af | |||
| dfdecb7e0b | |||
| 2b54414e60 | |||
| 2f03f95e9d | |||
| a828d714c6 | |||
| e36a3dd460 | |||
| b60fda3fec | |||
| 590b237338 | |||
| 237592fbda | |||
| 9a6a301c4f | |||
| 064c057200 | |||
| d1077e6171 | |||
| b90e483117 | |||
| ad25f4c43a | |||
| de22ae4a99 | |||
| d166463bca | |||
| ef326260c2 | |||
| a969e87f13 | |||
| 532fb73c43 | |||
| 0c79aa30ab | |||
| cd68572df5 | |||
| a37cc75bd7 | |||
| 3b8118ac0b | |||
| bdf725f86b | |||
| c8866b7d4c | |||
| 552b211124 | |||
| 680fe999b2 | |||
| 1e380374eb | |||
| 25705ad61b | |||
| 6351d5a283 | |||
| 1666e12db2 | |||
| 728cbcdff4 | |||
| bd047624e5 | |||
| 0e8f5b8147 | |||
| 45d4353cf4 | |||
| c7455ca776 | |||
| 5def0c2eea | |||
| 9e4090f601 | |||
| d1a8ecca70 | |||
| 69415616f8 | |||
| 7eec35e4ea | |||
| f76bf37229 | |||
| 5c335f3acc | |||
| 98f91f8b0a | |||
| 93e568b254 | |||
| e86579b576 | |||
| 672ffefb5f | |||
| c500a6704e | |||
| 3e0c355d7b | |||
| 87da1b2d0c | |||
| 0d45084914 | |||
| 9097433898 | |||
| 0b704e356f | |||
| d847d5b942 | |||
| 694c900cd4 | |||
| 9204086f41 | |||
| d8395dfeb6 | |||
| 39f84d7fe4 | |||
| bbc8c1121f | |||
| 383ffdfe0a | |||
| 8c89c1daf5 | |||
| 706337b8ea | |||
| 9f67477858 | |||
| b703d81561 | |||
| 9e8be6cd28 | |||
| 250960f771 | |||
| bbfb0d669c | |||
| ad14802227 | |||
| d5b1087fb8 | |||
| 150b7cd4e2 | |||
| 20fc8ee3cc | |||
| 47877ec70c | |||
| 91e8aca0a9 | |||
| f809cc2db7 | |||
| b07caa93c9 | |||
| a65c42b7d8 | |||
| 583006b599 | |||
| 29b5837a91 | |||
| 26eadad611 | |||
| 0aafa5a591 | |||
| 0a42863bd1 | |||
| a1f23f3a4c | |||
| badef10f41 | |||
| f1284bd73c | |||
| d2926d2edf | |||
| da45f02f6a | |||
| 67a3a7521f | |||
| 699f87c617 | |||
| a568ed2bd8 | |||
| 6b4366a0a4 | |||
| 5aa957bcff | |||
| f22b5abfac | |||
| 8811f5053d | |||
| b16571bb86 | |||
| d12cf29322 | |||
| 7c8c7984a1 | |||
| a35ddcd0e1 | |||
| ddc95bc7f7 | |||
| ce99a71a52 | |||
| 9882eef93a | |||
| 140667308d | |||
| f50859fd09 | |||
| 86267bd8d6 | |||
| e5f6738280 | |||
| d6acc8debe | |||
| 84c562de1c | |||
| ddd6bb632a | |||
| 85b69b8689 | |||
| b2837d38b8 | |||
| 06582b4cf9 | |||
| f5d0863b2e | |||
| f05c0cd6ce | |||
| 223642904f | |||
| 8317e918d9 | |||
| d497b62fb3 | |||
| 014ba087a8 | |||
| dfa1f480b5 | |||
| 9ce8fcd268 | |||
| 6bd07d3d63 | |||
| 125d820dac | |||
| f77f7e645b | |||
| 82bee848a1 | |||
| 41aa30c93f | |||
| 594c4102f6 | |||
| cf1ae599f1 | |||
| 9fbc499361 | |||
| 3d747571d6 | |||
| 036e02e052 | |||
| d03a9188ae | |||
| a07e6e4013 | |||
| ea0562c124 | |||
| 215b6cc634 | |||
| f7460dfa9c | |||
| 92a285378a | |||
| d033f2235f | |||
| 29016a1fe4 | |||
| d75596c9b8 | |||
| 8ef3f8ade3 | |||
| cdce807375 | |||
| 4c9cf84dff | |||
| f878e38d12 | |||
| 24c572b806 | |||
| abb05eae40 | |||
| 934271b272 | |||
| a3366e6c95 | |||
| 8971bf7546 | |||
| 3a673cc06e | |||
| 8bf09f65cf | |||
| b7f5699b3e | |||
| 7d01550649 | |||
| 05aedc7c57 | |||
| 9af5367aee | |||
| 3c1015942d | |||
| 98329144a0 | |||
| dc990a5309 | |||
| c28dc2bb13 | |||
| c3fa406d60 | |||
| 3c84312ac5 | |||
| a88656ea5a | |||
| 86ad0d2c62 | |||
| 5512567d74 | |||
| d14d7f67b3 | |||
| f6b8a150bb | |||
| ba8ab188d8 | |||
| b188f76b65 | |||
| 48a745e934 | |||
| e1c9cbedd7 | |||
| c53c5b47ea | |||
| 487ac04a1b | |||
| c98771f683 | |||
| 9f990349ff | |||
| 3aed6de76e | |||
| 1be7a45f18 | |||
| 531228f3c0 | |||
| 15a53269d2 | |||
| 7187639286 | |||
| fd72c74184 | |||
| 9912fce370 | |||
| 063850bc20 | |||
| fb8c1ad75b | |||
| 805c6b9711 | |||
| e3fbd46a79 | |||
| 9fc9ca3265 | |||
| 40aee428b5 | |||
| b7fe42a545 | |||
| 5cbd311e80 | |||
| 4f74bf88f1 | |||
| 4df999cbe2 | |||
| 039fe4bddf | |||
| 833bbc5b88 | |||
| c0dfc5bb89 | |||
| b1866205ed | |||
| 50067840c7 | |||
| aa6c9e7f21 | |||
| cf4991979d | |||
| 09cfdfd756 | |||
| 72970d8c7d | |||
| c3d320aa8c | |||
| 3fcbc847a9 | |||
| 151fc3065b | |||
| 7eeb8a2c0c | |||
| 93437e3539 | |||
| ae81396710 | |||
| 7a61b1f4b9 | |||
| 6fd2e6ced0 | |||
| f3ddaf5dce | |||
| 961b408f10 | |||
| 18c5a9aef4 | |||
| 880844d178 | |||
| f55cf6f90d | |||
| ea90b73781 | |||
| e81576b74e | |||
| 4de3380ca5 | |||
| 7f2ecfe721 | |||
| 62c00ba871 | |||
| d55c34f662 | |||
| 76821902c8 | |||
| 504fd3e282 | |||
| 86da74e0bc | |||
| 484bbcbfba | |||
| 500e3b9d85 | |||
| b299c85f98 | |||
| 6a39f5bd1c | |||
| 2cecd66a50 | |||
| ca15df807c | |||
| ce4d8d902d | |||
| 0f83413a8f | |||
| 12a5a2da41 | |||
| 15f53f6d97 | |||
| 40d78f97e6 | |||
| cbe9446e50 | |||
| 890e7beb26 | |||
| 72926fd4ee | |||
| 0d62f4706a | |||
| da20193852 | |||
| cdc07b5d4e | |||
| df0d018b40 | |||
| d02e5ecdc5 | |||
| 7ee96336d7 | |||
| 89ce14bfee | |||
| b5b6e9997d | |||
| 9ea12cf091 | |||
| 5d6ca51ea8 | |||
| 2d0a80bcbb | |||
| a2eea79ea8 | |||
| fe52062f04 | |||
| 6c4f5c78d0 | |||
| d7a65ae09f | |||
| e97a630235 | |||
| f66f15ce90 | |||
| 7b6b9a6e22 | |||
| 4d471306f4 | |||
| e3dbc609d1 | |||
| 67bb18921b | |||
| 83c75f9291 | |||
| fce606ed94 | |||
| 24a9663db4 | |||
| b7dba5f72b | |||
| 60d245e968 | |||
| 689324ad24 | |||
| 5a2d655c4a | |||
| a6b258c953 | |||
| 765df72a6e | |||
| 2b5b1b2a40 | |||
| 55b3776f42 | |||
| f36217fb92 | |||
| 6881dae3bc | |||
| 02c7630bbb | |||
| d80207d69e | |||
| 09a999c8a1 | |||
| e3dd66ddb4 | |||
| f36ffece70 | |||
| d6d74ef77f | |||
| 279c944628 | |||
| ff624c35e3 | |||
| a6deca4da8 | |||
| 14d5685528 | |||
| cb13201fd5 | |||
| e56b50474a | |||
| 83b94092b6 | |||
| fe8318d336 | |||
| 898c009f50 | |||
| b8bdc638bf | |||
| 3537b47ba8 | |||
| 9bde5a6482 | |||
| f8b7583de5 | |||
| d484fbd93c | |||
| 214e5cc6e3 | |||
| a6c123d4e4 | |||
| 363a438fc6 | |||
| 2c4975c5b5 | |||
| f8d96846d5 | |||
| a57fd395fe | |||
| 9feea24516 | |||
| 41f2b5ec8d | |||
| a8e9046c6c | |||
| 67b1db7123 | |||
| 2a59f5ce00 | |||
| 14cf2d9532 | |||
| c10d526385 | |||
| 32efce9f86 | |||
| 533d885923 | |||
| 9903dd5ad9 | |||
| ad5a85ed51 | |||
| f25e5a1012 | |||
| acb7148ac4 | |||
| 585c87a8c6 | |||
| 9d651f85f1 | |||
| ddef0a729d | |||
| 7a0b449ac3 | |||
| f8bcc9966d | |||
| f300ddcada | |||
| c28013930e | |||
| 45b820abe2 | |||
| 034177f0c0 | |||
| 5edbac54d3 | |||
| 09bf5ca5a0 | |||
| 814f9ebc5b | |||
| 6680975105 | |||
| dfdbcd8325 | |||
| 2820371a00 | |||
| 5f1d1869e3 | |||
| a60a4405c8 | |||
| 24d596ee53 | |||
| 0c37fcebe8 | |||
| 1ca7408701 | |||
| eceaf3bfb4 | |||
| 68f8d44e0d | |||
| ab5f27c5af | |||
| f7d074d64c | |||
| 6ad9366be0 | |||
| 32cea2e656 | |||
| 17cf16dd19 | |||
| f533541b67 | |||
| f4ccffc754 | |||
| 6a51e74319 | |||
| eb99d460a3 | |||
| 25a92406ce | |||
| e2f76ff8e3 | |||
| a7cfb276a6 | |||
| a26ea8134c | |||
| 892cf8be29 | |||
| 4880bc49e1 | |||
| 068eb252c5 | |||
| e784171e11 | |||
| 98db29d939 | |||
| 6fddeb89bc | |||
| e51810cb65 | |||
| 27ae0785c1 | |||
| 1dabea71da | |||
| e6fe79daca | |||
| dd54429ff6 | |||
| 47c9866131 | |||
| c39e8b142e | |||
| 1b54306b2f | |||
| 1a193d24ef | |||
| d27bdd02ef | |||
| 9474623ff0 | |||
| caf2439116 | |||
| 4ad507b4e9 | |||
| 9e61e71cb1 | |||
| 1176351701 | |||
| ed835a4973 | |||
| 641c7a6d57 | |||
| 8bfbdc8cf5 | |||
| eae27b0baa | |||
| 6281f981fa | |||
| ee08bfb6aa | |||
| 6a07109e10 | |||
| 28d18a4f70 | |||
| 14e81fca0e | |||
| 6d0cb74b64 | |||
| 29b40bc75f | |||
| d78bf5a93c | |||
| f37b21bf6c | |||
| 7309784487 | |||
| 55426fb047 | |||
| a1172b6211 | |||
| 271a865d01 | |||
| 5050dd13f4 | |||
| 5ce81bf386 | |||
| 40fd3e9ae2 | |||
| d8bffe12d7 | |||
| 7566aa2824 | |||
| c97ede5c34 | |||
| a2416f0b3f | |||
| 89eefbdc6a | |||
| 44f64a852b | |||
| 11ecb09eab | |||
| e6f686533f | |||
| c8dd7d95de | |||
| 81a7af5704 | |||
| e0dd754995 | |||
| 178e024721 | |||
| 99877adb39 | |||
| 5d8779fac2 | |||
| 34e07ef245 | |||
| c2f006f37a | |||
| f19506c3ce | |||
| 313a40875a | |||
| c49acaddf4 | |||
| e2487270e5 | |||
| 2a29b56b12 | |||
| 746c533c3c | |||
| 3ddd2445e5 | |||
| a682132503 | |||
| 00bee0fa54 | |||
| 4d25d2ffcc | |||
| 1db4a96c2c | |||
| 8fef15cd56 | |||
| 64396d15c8 | |||
| 5d209f798a | |||
| 811006ed8f | |||
| 555e9ed5fe | |||
| 49eb11e135 | |||
| a40cc0d9fc | |||
| 23078fe9c4 | |||
| 254c6dc993 | |||
| 66d0b809da | |||
| d0223dc1a0 | |||
| 876b58cebc | |||
| a21c2b4144 | |||
| b38bde7e12 | |||
| 5cce143273 | |||
| 75b97c9e0d | |||
| 91d3e9d924 | |||
| b6819aa8dd | |||
| 60cb12c062 | |||
| 8ea57a4b36 | |||
| dd96425a72 | |||
| 1bdcac1aac | |||
| 70443d06a2 | |||
| e23512d815 | |||
| 8db20a6589 | |||
| e7787b18d3 | |||
| 7f7bbbcfb4 | |||
| 6a966bdb61 | |||
| 702ac16d12 | |||
| 8c9150c223 | |||
| af4e13e528 | |||
| 8951032d07 | |||
| a5a64daf75 | |||
| b3e7510d31 | |||
| 4bc6b69a96 | |||
| 00b0d03dee | |||
| 1c24f3b14a | |||
| 65383f28a2 | |||
| ef1c63169e | |||
| 7cf1f011ef | |||
| 4aeeaed4c7 | |||
| ebe2f2b950 | |||
| 9998946886 | |||
| 0b16a37675 | |||
| f860b5a058 | |||
| 4f982ee3d1 | |||
| 5f4acdee0e | |||
| e640cc187b | |||
| d52fa9bcfc | |||
| 3029f0dd16 | |||
| 9f69d80b12 | |||
| 573e154c18 | |||
| ad49eea20d | |||
| 1dfb8ee3ce | |||
| bca57a4330 | |||
| ea483333f4 | |||
| 9f2d83c148 | |||
| 4a59e203cb | |||
| 697137585e | |||
| 8031ec9d89 | |||
| 54310ba2bc | |||
| 60a894bded | |||
| f40cbb06d6 | |||
| 01576229fe | |||
| 6ad505b6e4 | |||
| 9c79b55078 | |||
| aac231c39a | |||
| 6b577e1516 | |||
| 79b4503d01 | |||
| 1673a59a65 | |||
| ae395070d9 | |||
| eced38791a | |||
| 7d3c3cc1e3 | |||
| a26fdf3b54 | |||
| b162585beb | |||
| 77fb880f2d | |||
| 46222d488e | |||
| c0abe47d87 | |||
| d6321ab2a1 | |||
| ca1cc1c76e | |||
| 92593c3ea9 | |||
| 4b2a89683a | |||
| a830db6d86 | |||
| 7fb62aedc7 | |||
| c7fa954449 | |||
| a002e04838 | |||
| fe38bab63e | |||
| 86e0c29c25 | |||
| e554792ea5 | |||
| a82f60e302 | |||
| 072a7ac84a | |||
| 8dcfd7be61 | |||
| a401afe52e | |||
| f2ccc83a29 | |||
| b0ccf97226 | |||
| 77cccbc405 | |||
| 6370db0587 | |||
| b5c71915c7 | |||
| c96777369d | |||
| 9d663c5819 | |||
| 218eaf92ec | |||
| bbc31e07e9 | |||
| db889737be | |||
| d16ddf42cb | |||
| fa0f0bfad9 | |||
| 23e28fdd93 | |||
| cb62a3b039 | |||
| 0cb15dba0a | |||
| 48112f1a50 | |||
| b99290a060 | |||
| ce013119b9 | |||
| 851643110f | |||
| 45d9f292f9 | |||
| b3723ae020 | |||
| 498bb81c0a | |||
| cfbc1d6b70 | |||
| 7355272818 | |||
| 3c49b63a6b | |||
| db7b0a2272 | |||
| 42e99ac2eb | |||
| 6f86b4ec95 | |||
| 574b492479 | |||
| c9cf188e08 | |||
| b459a204a4 | |||
| a8ca4dbc3a | |||
| 21c4e4940b | |||
| ee6e44669f | |||
| b84cab3fc0 | |||
| a9edcb5f10 | |||
| ee207e2249 | |||
| 28f06953fc | |||
| 90e3024517 | |||
| 6222a3a8f7 | |||
| 14482a174b | |||
| a2395a0417 | |||
| fb2fc2f43f | |||
| dccd6a0499 | |||
| 01ffe94974 | |||
| 67f51b6e69 | |||
| 105eec0693 | |||
| ea4dd30143 | |||
| abfa841a98 | |||
| 1003c372bf | |||
| ff99823130 | |||
| fe431f1e8e | |||
| 2ee49802a9 | |||
| 2ab46f7fa3 | |||
| 77e721f7ce | |||
| d4d1491a81 | |||
| b2b86d2e04 | |||
| 3f3e7fd9f5 | |||
| deec9e9ac8 | |||
| 5634eaaf7a | |||
| 05f8a7bfb7 | |||
| c1aa4fc1d0 | |||
| 51570c73e1 | |||
| 6afafe1114 | |||
| c431a1e701 | |||
| 177103021e | |||
| 5dd4e8ff47 | |||
| 8b36b16b03 | |||
| b04ea483a8 | |||
| 55bb147862 | |||
| f2ba32a950 | |||
| 35c893e84f | |||
| cca9777064 | |||
| 2f386b6be2 | |||
| 6d19312f51 | |||
| a16b8a5474 | |||
| 27b72c4c89 | |||
| dbdce87679 | |||
| 2fd37df46a | |||
| 32a55c5c6e | |||
| 481a3f1ba1 | |||
| 74f6c56d27 | |||
| bcaf8c7e70 | |||
| d1f4eecc3a | |||
| 7f5fef431a | |||
| f6a0f2743e | |||
| 9b49ee6208 | |||
| 198e472ba3 | |||
| 4226ac02dc | |||
| 4606630f5a | |||
| 5d8d561565 | |||
| 6a6ac8b47b | |||
| 6417d7f882 | |||
| 93ee368556 | |||
| d89171768b | |||
| b73037a282 | |||
| 1888ac386f | |||
| 535958a274 | |||
| 35e1f2abed | |||
| 6e5cfde4b1 | |||
| 52828730cb | |||
| e3eae253df | |||
| 104123aa88 | |||
| 71224984bb | |||
| 181f4ab54c | |||
| 5d1f303a16 | |||
| 6a48348831 | |||
| 33be36f175 | |||
| 1a63b68990 | |||
| 1e3963b75d | |||
| ca290eeb97 | |||
| dbe7934931 | |||
| ca12278e90 | |||
| db0e93fa8e | |||
| c8a041fbeb | |||
| 273d14d8a0 | |||
| 024592281f | |||
| 5dbcca1543 | |||
| b57b079c9b |
+45
@@ -0,0 +1,45 @@
|
||||
boost_root
|
||||
.downloads-by-cmake
|
||||
common/netlist_keywords.*
|
||||
common/netlist_lexer.h
|
||||
common/pcb_plot_params_lexer.h
|
||||
common/page_layout/page_layout_reader_keywords.cpp
|
||||
common/fp_lib_table_keywords.*
|
||||
common/gal/opengl/shader_src.h
|
||||
include/fp_lib_table_lexer.h
|
||||
include/netlist_lexer.h
|
||||
include/page_layout_reader_lexer.h
|
||||
eeschema/cmp_library_lexer.h
|
||||
eeschema/cmp_library_keywords.*
|
||||
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
|
||||
eeschema/dialogs/dialog_bom_cfg_lexer.h
|
||||
eeschema/dialogs/dialog_bom_help_html.h
|
||||
eeschema/template_fieldnames_keywords.*
|
||||
eeschema/template_fieldnames_lexer.h
|
||||
pcbnew/dialogs/dialog_freeroute_exchange_help_html.h
|
||||
pcbnew/pcb_plot_params_keywords.cpp
|
||||
pcbnew/pcb_plot_params_lexer.h
|
||||
Makefile
|
||||
CMakeCache.txt
|
||||
auto_renamed_to_cpp
|
||||
Testing
|
||||
version.h
|
||||
config.h
|
||||
install_manifest.txt
|
||||
Documentation/doxygen
|
||||
*.bak
|
||||
common/pcb_plot_params_keywords.cpp
|
||||
include/pcb_plot_params_lexer.h
|
||||
pcbnew/specctra_keywords.cpp
|
||||
pcbnew/specctra_lexer.h
|
||||
pcb_calculator/pcb_calculator_datafile_keywords.cpp
|
||||
pcb_calculator/pcb_calculator_datafile_lexer.h
|
||||
new/html
|
||||
new/sch_lib_table_keywords.cpp
|
||||
new/sch_lib_table_lexer.h
|
||||
new/sweet_keywords.cpp
|
||||
new/sweet_lexer.h
|
||||
bitmaps_png/png*
|
||||
bitmaps_png/tmp
|
||||
common/pcb_keywords.cpp
|
||||
include/pcb_lexer.h
|
||||
@@ -1,5 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
Checks: '-clang-diagnostic-*,clang-analyzer-*, bugprone-*, modernize-deprecated-headers, modernize-loop-convert, modernize-use-override, modernize-redundant-void-arg, modernize-use-emplace, modernize-use-noexcept, modernize-use-bool-literals, modernize-pass-by-value, modernize-use-equals-default, modernize-use-equals-delete, modernize-use-default-member-init, cppcoreguidelines-prefer-member-initializer, cppcoreguidelines-init-variables, cppcoreguidelines-pro-type-member-init'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: 'file'
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
# Custom attribute to mark source files using KiCad C++ formatting
|
||||
[attr]kicad-cpp-source text=auto whitepace=tab-in-indent format.clang-format-kicad
|
||||
|
||||
# Custom attribute to mark KiCad's own CMake files
|
||||
[attr]kicad-cmake-source text=auto whitespace=tab-in-indent
|
||||
|
||||
# Custom attribute for auto-generated sources:
|
||||
# * Do not perform whitespace checking
|
||||
# * Do not format
|
||||
[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-kicad
|
||||
|
||||
# By default, all C and C++ files conform to KiCad formatting,
|
||||
# unless overridden
|
||||
*.c kicad-cpp-source
|
||||
*.cpp kicad-cpp-source
|
||||
*.h kicad-cpp-source
|
||||
|
||||
*.cmake kicad-cmake-source
|
||||
*.txt kicad-cmake-source
|
||||
*.md text=auto
|
||||
|
||||
# Compiled bitmap sources
|
||||
bitmaps_png/cpp_*/*.cpp generated
|
||||
|
||||
# wxFormBuilder-generated files
|
||||
**/dialog*/*_base.cpp generated
|
||||
**/dialog*/*_base.h generated
|
||||
|
||||
# Lemon grammars
|
||||
common/libeval/grammar.c generated
|
||||
common/libeval/grammar.h generated
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Git "hook chain", used to execute multiple scripts per hook.
|
||||
# To use:
|
||||
# * create a directory called <hookname>.d
|
||||
# * add scripts to this directory (executable)
|
||||
# * ln -s hook-chain <hookname>
|
||||
#
|
||||
# Now the scripts in that directory should be called in order.
|
||||
#
|
||||
# Set $HOOKCHAIN_DEBUG to see the names of invoked scripts.
|
||||
#
|
||||
# Based on script by Oliver Reflalo:
|
||||
# https://stackoverflow.com/questions/8730514/chaining-git-hooks
|
||||
#
|
||||
|
||||
hookname=`basename $0`
|
||||
|
||||
# Temp file for stdin, cleared at exit
|
||||
FILE=`mktemp`
|
||||
trap 'rm -f $FILE' EXIT
|
||||
cat - > $FILE
|
||||
|
||||
# Git hooks directory (this dir)
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# Execute hooks in the directory one by one
|
||||
for hook in $DIR/$hookname.d/*;
|
||||
do
|
||||
if [ -x "$hook" ]; then
|
||||
|
||||
if [ "$HOOKCHAIN_DEBUG" ]; then
|
||||
echo "Running hook $hook"
|
||||
fi
|
||||
|
||||
cat $FILE | $hook "$@"
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
echo "Hook $hook failed with error code $status"
|
||||
echo "To commit anyway, use --no-verify"
|
||||
exit $status
|
||||
else
|
||||
if [ "$HOOKCHAIN_DEBUG" ]; then
|
||||
echo "Hook passed: $hook"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -1 +0,0 @@
|
||||
hook-chain
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Runs clang-format on changed regions before commit.
|
||||
#
|
||||
# Remaining installation checks/instructions will be printed when you commit.
|
||||
#
|
||||
# Based on clang-format pre-commit hook by Alex Eagle
|
||||
# https://gist.github.com/alexeagle/c8ed91b14a407342d9a8e112b5ac7dab
|
||||
|
||||
# Set kicad.check-format to allow this hook to run
|
||||
# If not set, the hook always succeeds.
|
||||
|
||||
do_format=false
|
||||
|
||||
# Check if formatting is configured
|
||||
if [ "$(git config --get kicad.check-format)" = true ]; then
|
||||
do_format=true
|
||||
fi
|
||||
|
||||
# Older env variable method
|
||||
if [ ! -z "$KICAD_CHECK_FORMAT" ]; then
|
||||
do_format=true
|
||||
fi
|
||||
|
||||
if [ ! ${do_format} = true ]; then
|
||||
# No formatting required
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
check_clang_format() {
|
||||
if hash git-clang-format 2>/dev/null; then
|
||||
return
|
||||
else
|
||||
echo "SETUP ERROR: no git-clang-format executable found, or it is not executable"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_git_config() {
|
||||
if [[ "$(git config --get clangFormat.style)" != "file" ]]; then
|
||||
echo "SETUP ERROR: git config clangFormat.style is wrong (should be 'file'). Fix this with:"
|
||||
echo "git config clangFormat.style file"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
get_filtered_filenames()
|
||||
{
|
||||
format_attr='clang-format-kicad'
|
||||
|
||||
# command to get list of candidate files
|
||||
git_list_files='git diff --cached --name-only --diff-filter=ACM'
|
||||
|
||||
files=$(${git_list_files} |
|
||||
|
||||
# Filter for format-controlled files
|
||||
git check-attr --stdin format.${format_attr} |
|
||||
|
||||
# output only the file names
|
||||
grep ": set$" |
|
||||
cut -d: -f1)
|
||||
|
||||
echo ${files}
|
||||
}
|
||||
|
||||
check_clang_format
|
||||
check_git_config
|
||||
|
||||
files_to_check=$(get_filtered_filenames)
|
||||
|
||||
if [ -z "${files_to_check}" ]; then
|
||||
# No controlled files to check
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
git_clang_format_cmd="git clang-format -v --diff -- ${files_to_check}"
|
||||
|
||||
readonly out=$(${git_clang_format_cmd})
|
||||
|
||||
# In these cases, there is no formatting issues, so we succeed
|
||||
if [[ "$out" == *"no modified files to format"* ]]; then exit 0; fi
|
||||
if [[ "$out" == *"clang-format did not modify any files"* ]]; then exit 0; fi
|
||||
|
||||
# Any other case implies formatting results
|
||||
echo "ERROR: you need to run clang-format (e.g. using tools/check_coding.sh) on your commit"
|
||||
|
||||
# print the errors to show what's the issue
|
||||
${git_clang_format_cmd}
|
||||
|
||||
# fail the pre-commit
|
||||
exit 1
|
||||
@@ -1,2 +0,0 @@
|
||||
community_bridge: kicad
|
||||
custom: "https://donate.cernandsocietyfoundation.cern/b/my-donation?cid=4&_cv=1"
|
||||
@@ -1,26 +0,0 @@
|
||||
name: 'Redirect PRs'
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
lockdown:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v2
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
pr-comment: >
|
||||
Thank you for offering to help improve KiCad.
|
||||
This repository is a one-way mirror that can not accept pull requests.
|
||||
Please submit your merge request to the official KiCad repository
|
||||
at https://gitlab.com/kicad/code/kicad/-/merge_requests
|
||||
While we know that _your_ PR is not spam, we mark it as such to dissuade
|
||||
the Hacktoberfest PRs. Please join us over at GitLab. You can even use
|
||||
your GitHub credentials to log in there without creating a new account.
|
||||
skip-closed-pr-comment: true
|
||||
pr-labels: 'spam'
|
||||
close-pr: true
|
||||
lock-pr: true
|
||||
pr-lock-reason: 'spam'
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
.downloads-by-cmake
|
||||
.gdb_history
|
||||
boost_root
|
||||
/Build
|
||||
/build
|
||||
/cmake-build-*
|
||||
common/fp_lib_table_keywords.cpp
|
||||
common/drc_rules_keywords.cpp
|
||||
common/drc_rules_lexer.h
|
||||
common/netlist_keywords.*
|
||||
common/netlist_lexer.h
|
||||
common/pcb_plot_params_lexer.h
|
||||
common/drawing_sheet/drawing_sheet_reader_keywords.cpp
|
||||
common/lib_table_keywords.*
|
||||
common/gal/opengl/shader_src.h
|
||||
include/fp_lib_table_lexer.h
|
||||
include/lib_table_lexer.h
|
||||
include/netlist_lexer.h
|
||||
include/page_layout_reader_lexer.h
|
||||
eeschema/cmp_library_lexer.h
|
||||
eeschema/cmp_library_keywords.*
|
||||
eeschema/dialogs/dialog_bom_cfg_keywords.cpp
|
||||
eeschema/dialogs/dialog_bom_cfg_lexer.h
|
||||
common/template_fieldnames_keywords.cpp
|
||||
common/template_fieldnames_lexer.h
|
||||
eeschema/schematic_keywords.*
|
||||
pcbnew/pcb_plot_params_keywords.cpp
|
||||
pcbnew/pcb_plot_params_lexer.h
|
||||
Makefile
|
||||
CMakeCache.txt
|
||||
.cache/
|
||||
auto_renamed_to_cpp
|
||||
Testing
|
||||
version.h
|
||||
config.h
|
||||
install_manifest.txt
|
||||
doxygen/out
|
||||
*.bak
|
||||
*.pyc
|
||||
common/pcb_plot_params_keywords.cpp
|
||||
include/pcb_plot_params_lexer.h
|
||||
pcbnew/specctra_import_export/specctra_keywords.cpp
|
||||
pcbnew/specctra_import_export/specctra_lexer.h
|
||||
pcb_calculator/pcb_calculator_datafile_keywords.cpp
|
||||
pcb_calculator/pcb_calculator_datafile_lexer.h
|
||||
new/html
|
||||
new/sch_lib_table_keywords.cpp
|
||||
new/sch_lib_table_lexer.h
|
||||
new/sweet_keywords.cpp
|
||||
new/sweet_lexer.h
|
||||
bitmaps_png/tmp
|
||||
common/pcb_keywords.cpp
|
||||
include/pcb_lexer.h
|
||||
fp-info-cache
|
||||
|
||||
# demo project auxiliary files
|
||||
demos/**/*-bak
|
||||
demos/**/_autosave-*
|
||||
demos/**/fp-info-cache
|
||||
|
||||
# MacOS package info created by CMake
|
||||
bitmap2component/Info.plist
|
||||
cvpcb/Info.plist
|
||||
eeschema/Info.plist
|
||||
gerbview/Info.plist
|
||||
kicad/Info.plist
|
||||
pagelayout_editor/Info.plist
|
||||
pcb_calculator/Info.plist
|
||||
pcbnew/Info.plist
|
||||
|
||||
# editor/OS fluff
|
||||
.*.swp
|
||||
*~
|
||||
.idea
|
||||
.DS_Store
|
||||
*.png
|
||||
*.kiface
|
||||
*.o
|
||||
*.o.*
|
||||
*.a
|
||||
*.a.*
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.old
|
||||
*.gch
|
||||
*.orig
|
||||
*.patch
|
||||
|
||||
# These CMake files are wanted
|
||||
!cmake/**/*.cmake
|
||||
|
||||
# Eclipse IDE
|
||||
.settings/
|
||||
.project
|
||||
.cproject
|
||||
.pydevproject
|
||||
__pycache__
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
.editorconfig
|
||||
CMakeSettings.json
|
||||
.vscode/
|
||||
|
||||
# Sublime Text
|
||||
*.sublime-*
|
||||
|
||||
# KDevelop
|
||||
.kdev4/
|
||||
*.kdev4
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
i18n_status.svg
|
||||
i18n_status.csv
|
||||
|
||||
# Project local settings files and backups (in demos and qa tests)
|
||||
*.kicad_prl
|
||||
*-backups
|
||||
|
||||
# QA dataoutput
|
||||
qa/data/**/*.csv
|
||||
|
||||
# Don't actually ignore any of these files, since we need them in the tree
|
||||
!resources/linux/icons/hicolor/**/**/*
|
||||
!resources/linux/icons-nightly/hicolor/**/**/*
|
||||
!CMakeModules/**/*
|
||||
!resources/bitmaps_png/png/**/*
|
||||
|
||||
# Junk temp files generated by MSVC for resource files
|
||||
/resources/msw/RC*
|
||||
@@ -1,48 +0,0 @@
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- report
|
||||
|
||||
default:
|
||||
image:
|
||||
name: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:36
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Test the formatting in a merge request using clang-format
|
||||
##########################################################################
|
||||
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
|
||||
# so we must build the commit hash ourselves, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
|
||||
test_formatting:
|
||||
stage: test
|
||||
needs: []
|
||||
only:
|
||||
- merge_requests
|
||||
allow_failure: true
|
||||
before_script:
|
||||
# We must manually add the KiCad remote to ensure it is named sensibly
|
||||
- git remote add product https://gitlab.com/kicad/code/kicad.git ||
|
||||
git remote set-url product https://gitlab.com/kicad/code/kicad.git
|
||||
- git remote add source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git ||
|
||||
git remote set-url source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git
|
||||
- git fetch -n product
|
||||
- git fetch -n source
|
||||
# Get the SHAs of the commits
|
||||
- "TARGET_HEAD_SHA=$(git rev-parse product/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME})"
|
||||
- "SOURCE_HEAD_SHA=$(git rev-parse source/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME})"
|
||||
- "MERGE_BASE_SHA=$(git merge-base ${TARGET_HEAD_SHA} ${SOURCE_HEAD_SHA})"
|
||||
script:
|
||||
- echo "Testing formatting from commit ${MERGE_BASE_SHA}"
|
||||
- ./tools/check_coding.sh --diff --ci --commit ${MERGE_BASE_SHA}
|
||||
|
||||
|
||||
include:
|
||||
- local: '/.gitlab/templates.yml'
|
||||
- local: '/.gitlab/Fedora-Linux-CI.yml'
|
||||
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
|
||||
- local: '/.gitlab/Windows-CI.yml'
|
||||
- local: '/.gitlab/coverity.yml'
|
||||
- local: '/.gitlab/linux-metadata-validate.yml'
|
||||
- local: '/.gitlab/doxygen.yml'
|
||||
@@ -1,165 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Fedora and save the results
|
||||
##########################################################################
|
||||
.fedora_build_linux_base:
|
||||
stage: build
|
||||
# Don't tag until we have separate CI for MRs
|
||||
# tags:
|
||||
# - kicad-fedora
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
|
||||
extends: .only_code
|
||||
interruptible: false
|
||||
cache:
|
||||
key: "cache-fedora-linux"
|
||||
paths:
|
||||
- ccache/
|
||||
before_script:
|
||||
# CCache Config
|
||||
- mkdir -p ccache
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_BUILD_TYPE=QABUILD
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SPICE=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
../../
|
||||
- ninja 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/linux/3d-viewer/
|
||||
- build/linux/pcbnew/pcbnew.py
|
||||
- build/linux/pcbnew/_pcbnew.kiface
|
||||
- build/linux/pcbnew/_pcbnew.so
|
||||
- build/linux/qa/
|
||||
- build/linux/compilation_log.txt
|
||||
exclude:
|
||||
- build/linux/**/*.o
|
||||
- build/linux/**/*.a
|
||||
|
||||
# This split is to ensure we can always use our runner for our jobs
|
||||
fedora_build_linux_kicad:
|
||||
extends: .fedora_build_linux_base
|
||||
tags:
|
||||
- kicad-fedora
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_build_linux_public:
|
||||
extends: .fedora_build_linux_base
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
|
||||
# Upload the compilation log in an easily downloadable form
|
||||
.fedora_report_build_warn:
|
||||
stage: report
|
||||
extends: .only_code
|
||||
when: always
|
||||
script:
|
||||
- echo "Uploading compilation log"
|
||||
- cp build/linux/compilation_log.txt compilation_log.txt
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Build log'
|
||||
name: "build_log.txt"
|
||||
paths:
|
||||
- compilation_log.txt
|
||||
|
||||
fedora_report_build_warn_kicad:
|
||||
extends: .fedora_report_build_warn
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_report_build_warn_public:
|
||||
extends: .fedora_report_build_warn
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
|
||||
# Report on the metrics of the code
|
||||
.fedora_report_metrics:
|
||||
stage: report
|
||||
extends: .only_code
|
||||
when: always
|
||||
script:
|
||||
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_fedora_warnings "NR}' > metrics.txt
|
||||
- cat metrics.txt
|
||||
artifacts:
|
||||
reports:
|
||||
metrics: metrics.txt
|
||||
|
||||
fedora_report_metrics_kicad:
|
||||
extends: .fedora_report_metrics
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_report_metrics_public:
|
||||
extends: .fedora_report_metrics
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
##########################################################################
|
||||
# Run the code unit tests.
|
||||
##########################################################################
|
||||
.fedora_qa:
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
|
||||
extends:
|
||||
- .unit_test
|
||||
- .only_code
|
||||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step]
|
||||
|
||||
fedora_qa_kicad:
|
||||
extends: .fedora_qa
|
||||
tags:
|
||||
- kicad-fedora
|
||||
needs:
|
||||
- job: fedora_build_linux_kicad
|
||||
artifacts: true
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
|
||||
fedora_qa_public:
|
||||
extends: .fedora_qa
|
||||
needs:
|
||||
- job: fedora_build_linux_public
|
||||
artifacts: true
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_ROOT_NAMESPACE == "kicad"
|
||||
@@ -1,119 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Ubuntu 20.04 and save the results
|
||||
##########################################################################
|
||||
.ubuntu20.04_build:
|
||||
stage: build
|
||||
tags:
|
||||
- kicad-ubuntu20.04
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
interruptible: false
|
||||
cache:
|
||||
key: "cache-ubuntu20.04-linux"
|
||||
paths:
|
||||
- ccache/
|
||||
before_script:
|
||||
# CCache Config
|
||||
- mkdir -p ccache
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-G Ninja
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_USE_OCC=ON
|
||||
-DKICAD_SPICE=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON
|
||||
../../
|
||||
- ninja 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/linux/3d-viewer/
|
||||
- build/linux/pcbnew/pcbnew.py
|
||||
- build/linux/pcbnew/_pcbnew.kiface
|
||||
- build/linux/pcbnew/_pcbnew.so
|
||||
- build/linux/qa/
|
||||
- build/linux/compilation_log.txt
|
||||
exclude:
|
||||
- build/linux/**/*.o
|
||||
- build/linux/**/*.a
|
||||
|
||||
# Upload the compilation log in an easily downloadable form
|
||||
.ubuntu20.04_report_build_warn:
|
||||
stage: report
|
||||
when: always
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
script:
|
||||
- echo "Uploading compilation log"
|
||||
- cp build/linux/compilation_log.txt compilation_log.txt
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Build log'
|
||||
name: "build_log.txt"
|
||||
paths:
|
||||
- compilation_log.txt
|
||||
|
||||
# Report on the metrics of the code
|
||||
.ubuntu20.04_report_metrics:
|
||||
stage: report
|
||||
when: always
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
script:
|
||||
- cat build/linux/compilation_log.txt | { grep "warning:" || test $? = 1; } | awk 'END{print "number_of_ubuntu_20.04_warnings "NR}' > metrics.txt
|
||||
- cat metrics.txt
|
||||
artifacts:
|
||||
reports:
|
||||
metrics: metrics.txt
|
||||
|
||||
##########################################################################
|
||||
# Run the code unit tests.
|
||||
##########################################################################
|
||||
.ubuntu20.04_qa:
|
||||
extends:
|
||||
- .unit_test
|
||||
needs:
|
||||
- job: ubuntu20.04_build
|
||||
artifacts: true
|
||||
tags:
|
||||
- kicad-ubuntu20.04
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/ubuntu:20.04
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
except:
|
||||
- schedules
|
||||
parallel:
|
||||
matrix:
|
||||
# The name of the test without the qa_ prefix
|
||||
- TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step]
|
||||
@@ -1,47 +0,0 @@
|
||||
##########################################################################
|
||||
# Build KiCad on Windows and save the results
|
||||
##########################################################################
|
||||
win64_build:
|
||||
stage: build
|
||||
tags:
|
||||
- kicad-windows-1809
|
||||
extends: .only_code
|
||||
interruptible: false
|
||||
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/win1809-msvc:latest
|
||||
variables:
|
||||
VCPKG_BINARY_SOURCES: 'nuget,kicad,readwrite'
|
||||
cache:
|
||||
key: win64-vcpkg-"$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- build\windows\vcpkg_installed
|
||||
- .vcpkgCache
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
script:
|
||||
- C:\builder\build.ps1 -Env -Arch x64
|
||||
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
|
||||
- nuget.exe sources add -Name kicad -Source "https://nuget.kicad.org:443/v3/index.json"
|
||||
- nuget.exe setapikey $env:KICAD_NUGET_KEY -Source "https://nuget.kicad.org:443/v3/index.json"
|
||||
- mkdir -p build/windows -Force
|
||||
- cd build/windows
|
||||
- cmake `
|
||||
-G "Ninja" `
|
||||
-DCMAKE_TOOLCHAIN_FILE=C:\builder\vcpkg\scripts\buildsystems\vcpkg.cmake `
|
||||
-DCMAKE_BUILD_TYPE=Debug `
|
||||
-DKICAD_SCRIPTING_WXPYTHON=OFF `
|
||||
-DKICAD_USE_OCC=ON `
|
||||
-DKICAD_SPICE=ON `
|
||||
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON `
|
||||
-DKICAD_USE_3DCONNEXION=ON `
|
||||
../../
|
||||
- cmake --build . 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
# artifact.
|
||||
expire_in: 2 hrs
|
||||
when: always
|
||||
paths:
|
||||
- build/windows/compilation_log.txt
|
||||
@@ -1,70 +0,0 @@
|
||||
# This script is responsible for configuring the coverity file from the cache
|
||||
# (e.g. extracting it or updating it if needed)
|
||||
.coverity_cache_prep: &coverity_cache_prep |
|
||||
echo "Downloading MD5 hash of current Coverity Scan version to compare against cache"
|
||||
curl --output cov-analysis-linux64.md5 https://scan.coverity.com/download/linux64 \
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN \
|
||||
--form md5=1
|
||||
echo " *cov-analysis-linux64.tgz" >> cov-analysis-linux64.md5
|
||||
(md5sum --ignore-missing -c cov-analysis-linux64.md5) || (
|
||||
echo "Downloading new Coverity Scan version"
|
||||
curl --output cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 \
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN
|
||||
)
|
||||
echo "Extracting Coverity Scan"
|
||||
mkdir coverity/
|
||||
tar xzf cov-analysis-linux64.tgz --strip-components=1 -C coverity
|
||||
test -d coverity/bin
|
||||
|
||||
# This script is responsible for tar'ing and submitting the results of the build.
|
||||
# These results will be saved for 1 day if the build fails.
|
||||
.coverity_submit: &coverity_submit |
|
||||
echo "Creating tar file of scan results"
|
||||
tar cfz cov-int.tar.gz cov-int
|
||||
echo "Submitting scan results"
|
||||
export KICAD_VERSION=$(sed 's/[()]//g' kicad_build_version.txt)
|
||||
curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME \
|
||||
--form token=$COVERITY_SCAN_TOKEN \
|
||||
--form email=$GITLAB_USER_EMAIL \
|
||||
--form file=@cov-int.tar.gz \
|
||||
--form version="$KICAD_VERSION" \
|
||||
--form description="$KICAD_VERSION / $CI_COMMIT_TITLE" 2>&1 \
|
||||
| tee curl-response.txt
|
||||
grep -q 'Build successfully submitted' curl-response.txt
|
||||
|
||||
|
||||
Coverity:
|
||||
tags:
|
||||
- coverity
|
||||
stage: build
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
|
||||
only:
|
||||
refs:
|
||||
- schedules
|
||||
variables:
|
||||
- $SCHEDULED_JOB_NAME == "coverity"
|
||||
cache:
|
||||
key: coverity
|
||||
paths:
|
||||
- cov-analysis-linux64.tgz
|
||||
before_script:
|
||||
- export COVERITY_SCAN_PROJECT_NAME="kicad"
|
||||
- test "$(git rev-parse --is-shallow-repository)" = "false" || (git fetch --unshallow)
|
||||
- git fetch origin
|
||||
script:
|
||||
- *coverity_cache_prep
|
||||
- cmake
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_SPICE=ON
|
||||
- coverity/bin/cov-build --dir cov-int make -j8
|
||||
- *coverity_submit
|
||||
artifacts:
|
||||
expire_in: 1 year
|
||||
expose_as: 'Coverity log'
|
||||
name: "coverity_log.txt"
|
||||
paths:
|
||||
- cov-int/build-log.txt
|
||||
@@ -1,18 +0,0 @@
|
||||
build_doxygen_docker:
|
||||
image: docker:stable
|
||||
services:
|
||||
- docker:dind
|
||||
stage: build
|
||||
tags:
|
||||
- docker
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
|
||||
script:
|
||||
- docker build -t "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH" -f ./doxygen/doxygen.Dockerfile .
|
||||
- docker push "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH"
|
||||
only:
|
||||
refs:
|
||||
- schedules
|
||||
variables:
|
||||
- $SCHEDULED_JOB_NAME == "doxygen"
|
||||
@@ -1,20 +0,0 @@
|
||||
<!-- --------Before Creating a New Issue-----------
|
||||
* Limit report to a single issue.
|
||||
* Search the issue tracker to verify the issue has not already been reported.
|
||||
* Complete all instructions between `template comment markers <>.
|
||||
* Keep report contents limited to the necessary information required to fix the issue.
|
||||
* When creating an issue against the stable version of KiCad, make sure the latest available stable version is installed as issues may have already been resolved in later stable versions. -->
|
||||
# Description
|
||||
<!-- What is the current behavior and what is the expected behavior? -->
|
||||
<!-- If the issue is visual/graphical, please attach screenshots of the problem. -->
|
||||
<!-- Add the issue details below this line and before the "Steps to reproduce" heading. -->
|
||||
|
||||
# Steps to reproduce
|
||||
<!-- If there are multiple steps to reproduce it or it is a visual issue, then providing a screen recording as an attachment to this report is recommended. -->
|
||||
<!-- If this issue is specific to a project, please attach the necessary files to this issue. -->
|
||||
<!-- Add the steps to reproduce using the numbers below -->
|
||||
<!-- Add new step numbers before the "KiCad Version" heading. -->
|
||||
1.
|
||||
|
||||
# KiCad Version
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
##########################################################################
|
||||
# Run a validation of the metadata files for Linux
|
||||
##########################################################################
|
||||
validate_linux_metadata:
|
||||
stage: test
|
||||
needs: []
|
||||
interruptible: false
|
||||
# This is the only CI image with the utilities needed for this test
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/master/fedora:37
|
||||
# Due to bug https://github.com/hughsie/appstream-glib/issues/381, this doesn't think our description tag
|
||||
# is localized even though it actually is.
|
||||
allow_failure: true
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- branches
|
||||
- merge_requests
|
||||
- pushes
|
||||
changes:
|
||||
# Only run if the resources, its tests, or the translations are updated
|
||||
- resources/linux/**/*
|
||||
- qa/resources/linux/**/*
|
||||
- translation/**/*
|
||||
except:
|
||||
- schedules
|
||||
# Only build the metadata files in this CI job
|
||||
script:
|
||||
- mkdir -p build/linux
|
||||
- cd build/linux
|
||||
- cmake
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DKICAD_STDLIB_LIGHT_DEBUG=ON
|
||||
-DKICAD_SCRIPTING_WXPYTHON=ON
|
||||
-DKICAD_SPICE=ON
|
||||
-DKICAD_BUILD_I18N=ON
|
||||
../../
|
||||
- make metadata
|
||||
- cd ../../
|
||||
- ./qa/resources/linux/verifyMetadataFiles.sh ./ ./build/linux
|
||||
@@ -1,25 +0,0 @@
|
||||
##########################################################################
|
||||
# Test the formatting in a merge request using clang-format
|
||||
##########################################################################
|
||||
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
|
||||
# so we must build the commit hash ourselves, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
|
||||
test_formatting:
|
||||
stage: test
|
||||
needs: []
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
allow_failure: true
|
||||
before_script:
|
||||
# We must manually add the KiCad remote to ensure it is named sensibly
|
||||
- git remote add product https://gitlab.com/kicad/code/kicad.git
|
||||
- git remote add source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git
|
||||
- git fetch -n product
|
||||
- git fetch -n source
|
||||
# Get the SHAs of the commits
|
||||
- "TARGET_HEAD_SHA=$(git rev-parse product/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME})"
|
||||
- "SOURCE_HEAD_SHA=$(git rev-parse source/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME})"
|
||||
- "MERGE_BASE_SHA=$(git merge-base ${TARGET_HEAD_SHA} ${SOURCE_HEAD_SHA})"
|
||||
script:
|
||||
- echo "Testing formatting from commit ${MERGE_BASE_SHA}"
|
||||
- ./tools/check_coding.sh --diff --ci --commit ${MERGE_BASE_SHA}
|
||||
@@ -1,37 +0,0 @@
|
||||
##########################################################################
|
||||
# This will allow the job to run whenever code events trigger it.
|
||||
##########################################################################
|
||||
.only_code:
|
||||
only:
|
||||
- master
|
||||
- branches
|
||||
- merge_requests
|
||||
- pushes
|
||||
except:
|
||||
- schedules
|
||||
|
||||
##########################################################################
|
||||
# Define a template for all the unit tests, since each one is run in a separate
|
||||
# job to make the display nicer.
|
||||
##########################################################################
|
||||
.unit_test:
|
||||
stage: test
|
||||
when: on_success
|
||||
# We define this using a before script because GitLab cannot merge variable
|
||||
# definitions across inheritance (so the variables block from this would disappear)
|
||||
before_script:
|
||||
- export BOOST_TEST_LOGGER='JUNIT,all,test_results.${TEST}.xml:HRF,warning'
|
||||
- export CTEST_OUTPUT_ON_FAILURE=1
|
||||
script:
|
||||
- cd build/linux/qa
|
||||
- ctest -R qa_${TEST}
|
||||
# GitLab supports displaying the results in the GUI through JUNIT artifacts
|
||||
# (https://docs.gitlab.com/ee/ci/junit_test_reports.html)
|
||||
# so we upload the JUNIT results. Note that there is a bug with how paths
|
||||
# are processed in the junit report (https://gitlab.com/gitlab-org/gitlab/-/issues/23835)
|
||||
# so we can't use a glob and have to list out each hierarchy separately.
|
||||
artifacts:
|
||||
reports:
|
||||
junit:
|
||||
- build/linux/qa/*/*.xml
|
||||
- build/linux/qa/*/*/*.xml
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_aux.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <trigo.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
|
||||
#include <class_board_design_settings.h>
|
||||
#include <class_zone.h>
|
||||
#include <class_text_mod.h>
|
||||
#include <class_module.h>
|
||||
#include <class_drawsegment.h>
|
||||
#include <class_pcb_text.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
|
||||
// Exported function:
|
||||
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
|
||||
|
||||
|
||||
void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices )
|
||||
{
|
||||
unsigned ii;
|
||||
|
||||
/* adjust object scale, rotation and offset position */
|
||||
for( ii = 0; ii < aVertices.size(); ii++ )
|
||||
{
|
||||
aVertices[ii].x *= m_MatScale.x;
|
||||
aVertices[ii].y *= m_MatScale.y;
|
||||
aVertices[ii].z *= m_MatScale.z;
|
||||
|
||||
// adjust rotation
|
||||
if( m_MatRotation.x )
|
||||
RotatePoint( &aVertices[ii].y, &aVertices[ii].z, m_MatRotation.x * 10 );
|
||||
|
||||
if( m_MatRotation.y )
|
||||
RotatePoint( &aVertices[ii].z, &aVertices[ii].x, m_MatRotation.y * 10 );
|
||||
|
||||
if( m_MatRotation.z )
|
||||
RotatePoint( &aVertices[ii].x, &aVertices[ii].y, m_MatRotation.z * 10 );
|
||||
|
||||
/* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
|
||||
#define SCALE_3D_CONV ((IU_PER_MILS * 1000) / UNITS3D_TO_UNITSPCB)
|
||||
aVertices[ii].x += m_MatPosition.x * SCALE_3D_CONV;
|
||||
aVertices[ii].y += m_MatPosition.y * SCALE_3D_CONV;
|
||||
aVertices[ii].z += m_MatPosition.z * SCALE_3D_CONV;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits )
|
||||
{
|
||||
unsigned ii;
|
||||
GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;
|
||||
|
||||
/* ignore faces with less than 3 points */
|
||||
if( aVertices.size() < 3 )
|
||||
return;
|
||||
|
||||
/* calculate normal direction */
|
||||
ax = aVertices[1].x - aVertices[0].x;
|
||||
ay = aVertices[1].y - aVertices[0].y;
|
||||
az = aVertices[1].z - aVertices[0].z;
|
||||
|
||||
bx = aVertices[aVertices.size() - 1].x - aVertices[0].x;
|
||||
by = aVertices[aVertices.size() - 1].y - aVertices[0].y;
|
||||
bz = aVertices[aVertices.size() - 1].z - aVertices[0].z;
|
||||
|
||||
nx = ay * bz - az * by;
|
||||
ny = az * bx - ax * bz;
|
||||
nz = ax * by - ay * bx;
|
||||
|
||||
r = sqrt( nx * nx + ny * ny + nz * nz );
|
||||
|
||||
if( r >= 0.000001 ) /* avoid division by zero */
|
||||
{
|
||||
nx /= r;
|
||||
ny /= r;
|
||||
nz /= r;
|
||||
glNormal3f( nx, ny, nz );
|
||||
}
|
||||
|
||||
/* glBegin/glEnd */
|
||||
switch( aVertices.size() )
|
||||
{
|
||||
case 3:
|
||||
glBegin( GL_TRIANGLES );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
glBegin( GL_QUADS );
|
||||
break;
|
||||
|
||||
default:
|
||||
glBegin( GL_POLYGON );
|
||||
break;
|
||||
}
|
||||
|
||||
/* draw polygon/triangle/quad */
|
||||
for( ii = 0; ii < aVertices.size(); ii++ )
|
||||
{
|
||||
glVertex3d( aVertices[ii].x * aBiuTo3DUnits,
|
||||
aVertices[ii].y * aBiuTo3DUnits,
|
||||
aVertices[ii].z * aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
GLuint EDA_3D_CANVAS::DisplayCubeforTest()
|
||||
{
|
||||
GLuint gllist = glGenLists( 1 );
|
||||
|
||||
glNewList( gllist, GL_COMPILE_AND_EXECUTE );
|
||||
/* draw six faces of a cube */
|
||||
glBegin( GL_QUADS );
|
||||
glNormal3f( 0.0F, 0.0F, 1.0F );
|
||||
glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F );
|
||||
glVertex3f( -0.5F, -0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F );
|
||||
|
||||
glNormal3f( 0.0F, 0.0F, -1.0F );
|
||||
glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F );
|
||||
glVertex3f( 0.5F, 0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F );
|
||||
|
||||
glNormal3f( 0.0F, 1.0F, 0.0F );
|
||||
glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F );
|
||||
glVertex3f( -0.5F, 0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F );
|
||||
|
||||
glNormal3f( 0.0F, -1.0F, 0.0F );
|
||||
glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F );
|
||||
glVertex3f( 0.5F, -0.5F, 0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F );
|
||||
|
||||
glNormal3f( 1.0F, 0.0F, 0.0F );
|
||||
glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F );
|
||||
glVertex3f( 0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F );
|
||||
|
||||
glNormal3f( -1.0F, 0.0F, 0.0F );
|
||||
glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F );
|
||||
glVertex3f( -0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F );
|
||||
glEnd();
|
||||
|
||||
glEndList();
|
||||
|
||||
return gllist;
|
||||
}
|
||||
|
||||
VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer )
|
||||
{
|
||||
wxString text;
|
||||
|
||||
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
|
||||
gridSizer->AddGrowableCol( 1 );
|
||||
gridSizer->SetFlexibleDirection( wxHORIZONTAL );
|
||||
gridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
aBoxSizer->Add( gridSizer, 0, wxEXPAND, 5 );
|
||||
|
||||
wxStaticText* msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "X:" ) );
|
||||
gridSizer->Add( msgtitle, 0, wxALL , 5 );
|
||||
|
||||
m_XValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition,wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_XValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Y:" ), wxDefaultPosition,
|
||||
wxDefaultSize, 0 );
|
||||
gridSizer->Add( msgtitle, 0, wxALL, 5 );
|
||||
|
||||
m_YValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition, wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_YValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
msgtitle = new wxStaticText( aParent, wxID_ANY, wxT( "Z:" ), wxDefaultPosition,
|
||||
wxDefaultSize, 0 );
|
||||
gridSizer->Add( msgtitle, 0, wxALL, 5 );
|
||||
|
||||
m_ZValueCtrl = new wxTextCtrl( aParent, wxID_ANY, wxEmptyString,
|
||||
wxDefaultPosition, wxDefaultSize, 0 );
|
||||
gridSizer->Add( m_ZValueCtrl, 0, wxALL|wxEXPAND, 5 );
|
||||
}
|
||||
|
||||
|
||||
VERTEX_VALUE_CTRL::~VERTEX_VALUE_CTRL()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
S3D_VERTEX VERTEX_VALUE_CTRL::GetValue()
|
||||
{
|
||||
S3D_VERTEX value;
|
||||
double dtmp;
|
||||
|
||||
m_XValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.x = dtmp;
|
||||
m_YValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.y = dtmp;
|
||||
m_ZValueCtrl->GetValue().ToDouble( &dtmp );
|
||||
value.z = dtmp;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void VERTEX_VALUE_CTRL::SetValue( S3D_VERTEX vertex )
|
||||
{
|
||||
wxString text;
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.x );
|
||||
m_XValueCtrl->Clear();
|
||||
m_XValueCtrl->AppendText( text );
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.y );
|
||||
m_YValueCtrl->Clear();
|
||||
m_YValueCtrl->AppendText( text );
|
||||
|
||||
text.Printf( wxT( "%f" ), vertex.z );
|
||||
m_ZValueCtrl->Clear();
|
||||
m_ZValueCtrl->AppendText( text );
|
||||
}
|
||||
|
||||
|
||||
void VERTEX_VALUE_CTRL::Enable( bool onoff )
|
||||
{
|
||||
m_XValueCtrl->Enable( onoff );
|
||||
m_YValueCtrl->Enable( onoff );
|
||||
m_ZValueCtrl->Enable( onoff );
|
||||
}
|
||||
@@ -1,759 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022 CERN
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/datetime.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 106800
|
||||
#include <boost/uuid/detail/sha1.hpp>
|
||||
#else
|
||||
#include <boost/uuid/sha1.hpp>
|
||||
#endif
|
||||
|
||||
#include "3d_cache.h"
|
||||
#include "3d_info.h"
|
||||
#include "3d_plugin_manager.h"
|
||||
#include "sg/scenegraph.h"
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <common.h> // For ExpandEnvVarSubstitutions
|
||||
#include <filename_resolver.h>
|
||||
#include <paths.h>
|
||||
#include <pgm_base.h>
|
||||
#include <project.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <wx_filename.h>
|
||||
|
||||
|
||||
#define MASK_3D_CACHE "3D_CACHE"
|
||||
|
||||
static std::mutex mutex3D_cache;
|
||||
static std::mutex mutex3D_cacheManager;
|
||||
|
||||
|
||||
static bool isSHA1Same( const unsigned char* shaA, const unsigned char* shaB ) noexcept
|
||||
{
|
||||
for( int i = 0; i < 20; ++i )
|
||||
{
|
||||
if( shaA[i] != shaB[i] )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool checkTag( const char* aTag, void* aPluginMgrPtr )
|
||||
{
|
||||
if( nullptr == aTag || nullptr == aPluginMgrPtr )
|
||||
return false;
|
||||
|
||||
S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr;
|
||||
|
||||
return pp->CheckTag( aTag );
|
||||
}
|
||||
|
||||
|
||||
static const wxString sha1ToWXString( const unsigned char* aSHA1Sum )
|
||||
{
|
||||
unsigned char uc;
|
||||
unsigned char tmp;
|
||||
char sha1[41];
|
||||
int j = 0;
|
||||
|
||||
for( int i = 0; i < 20; ++i )
|
||||
{
|
||||
uc = aSHA1Sum[i];
|
||||
tmp = uc / 16;
|
||||
|
||||
if( tmp > 9 )
|
||||
tmp += 87;
|
||||
else
|
||||
tmp += 48;
|
||||
|
||||
sha1[j++] = tmp;
|
||||
tmp = uc % 16;
|
||||
|
||||
if( tmp > 9 )
|
||||
tmp += 87;
|
||||
else
|
||||
tmp += 48;
|
||||
|
||||
sha1[j++] = tmp;
|
||||
}
|
||||
|
||||
sha1[j] = 0;
|
||||
|
||||
return wxString::FromUTF8Unchecked( sha1 );
|
||||
}
|
||||
|
||||
|
||||
class S3D_CACHE_ENTRY
|
||||
{
|
||||
public:
|
||||
S3D_CACHE_ENTRY();
|
||||
~S3D_CACHE_ENTRY();
|
||||
|
||||
void SetSHA1( const unsigned char* aSHA1Sum );
|
||||
const wxString GetCacheBaseName();
|
||||
|
||||
wxDateTime modTime; // file modification time
|
||||
unsigned char sha1sum[20];
|
||||
std::string pluginInfo; // PluginName:Version string
|
||||
SCENEGRAPH* sceneData;
|
||||
S3DMODEL* renderData;
|
||||
|
||||
private:
|
||||
// prohibit assignment and default copy constructor
|
||||
S3D_CACHE_ENTRY( const S3D_CACHE_ENTRY& source );
|
||||
S3D_CACHE_ENTRY& operator=( const S3D_CACHE_ENTRY& source );
|
||||
|
||||
wxString m_CacheBaseName; // base name of cache file (a SHA1 digest)
|
||||
};
|
||||
|
||||
|
||||
S3D_CACHE_ENTRY::S3D_CACHE_ENTRY()
|
||||
{
|
||||
sceneData = nullptr;
|
||||
renderData = nullptr;
|
||||
memset( sha1sum, 0, 20 );
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE_ENTRY::~S3D_CACHE_ENTRY()
|
||||
{
|
||||
delete sceneData;
|
||||
|
||||
if( nullptr != renderData )
|
||||
S3D::Destroy3DModel( &renderData );
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE_ENTRY::SetSHA1( const unsigned char* aSHA1Sum )
|
||||
{
|
||||
if( nullptr == aSHA1Sum )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] NULL passed for aSHA1Sum" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy( sha1sum, aSHA1Sum, 20 );
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_CACHE_ENTRY::GetCacheBaseName()
|
||||
{
|
||||
if( m_CacheBaseName.empty() )
|
||||
m_CacheBaseName = sha1ToWXString( sha1sum );
|
||||
|
||||
return m_CacheBaseName;
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE::S3D_CACHE()
|
||||
{
|
||||
m_FNResolver = new FILENAME_RESOLVER;
|
||||
m_project = nullptr;
|
||||
m_Plugins = new S3D_PLUGIN_MANAGER;
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE::~S3D_CACHE()
|
||||
{
|
||||
FlushCache();
|
||||
|
||||
delete m_FNResolver;
|
||||
delete m_Plugins;
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePath,
|
||||
S3D_CACHE_ENTRY** aCachePtr )
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = nullptr;
|
||||
|
||||
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile, aBasePath );
|
||||
|
||||
if( full3Dpath.empty() )
|
||||
{
|
||||
// the model cannot be found; we cannot proceed
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [3D model] could not find model '%s'\n" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aModelFile );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// check cache if file is already loaded
|
||||
std::lock_guard<std::mutex> lock( mutex3D_cache );
|
||||
|
||||
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
|
||||
mi = m_CacheMap.find( full3Dpath );
|
||||
|
||||
if( mi != m_CacheMap.end() )
|
||||
{
|
||||
wxFileName fname( full3Dpath );
|
||||
|
||||
if( fname.FileExists() ) // Only check if file exists. If not, it will
|
||||
{ // use the same model in cache.
|
||||
bool reload = ADVANCED_CFG::GetCfg().m_Skip3DModelMemoryCache;
|
||||
wxDateTime fmdate = fname.GetModificationTime();
|
||||
|
||||
if( fmdate != mi->second->modTime )
|
||||
{
|
||||
unsigned char hashSum[20];
|
||||
getSHA1( full3Dpath, hashSum );
|
||||
mi->second->modTime = fmdate;
|
||||
|
||||
if( !isSHA1Same( hashSum, mi->second->sha1sum ) )
|
||||
{
|
||||
mi->second->SetSHA1( hashSum );
|
||||
reload = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( reload )
|
||||
{
|
||||
if( nullptr != mi->second->sceneData )
|
||||
{
|
||||
S3D::DestroyNode( mi->second->sceneData );
|
||||
mi->second->sceneData = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != mi->second->renderData )
|
||||
S3D::Destroy3DModel( &mi->second->renderData );
|
||||
|
||||
mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath,
|
||||
mi->second->pluginInfo );
|
||||
}
|
||||
}
|
||||
|
||||
if( nullptr != aCachePtr )
|
||||
*aCachePtr = mi->second;
|
||||
|
||||
return mi->second->sceneData;
|
||||
}
|
||||
|
||||
// a cache item does not exist; search the Filename->Cachename map
|
||||
return checkCache( full3Dpath, aCachePtr );
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile, const wxString& aBasePath )
|
||||
{
|
||||
return load( aModelFile, aBasePath );
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr )
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = nullptr;
|
||||
|
||||
unsigned char sha1sum[20];
|
||||
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
|
||||
m_CacheList.push_back( ep );
|
||||
wxFileName fname( aFileName );
|
||||
ep->modTime = fname.GetModificationTime();
|
||||
|
||||
if( !getSHA1( aFileName, sha1sum ) || m_CacheDir.empty() )
|
||||
{
|
||||
// just in case we can't get a hash digest (for example, on access issues)
|
||||
// or we do not have a configured cache file directory, we create an
|
||||
// entry to prevent further attempts at loading the file
|
||||
|
||||
if( m_CacheMap.emplace( aFileName, ep ).second == false )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
m_CacheList.pop_back();
|
||||
delete ep;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aCachePtr )
|
||||
*aCachePtr = ep;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( m_CacheMap.emplace( aFileName, ep ).second == false )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
m_CacheList.pop_back();
|
||||
delete ep;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( aCachePtr )
|
||||
*aCachePtr = ep;
|
||||
|
||||
ep->SetSHA1( sha1sum );
|
||||
|
||||
wxString bname = ep->GetCacheBaseName();
|
||||
wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && wxFileName::FileExists( cachename )
|
||||
&& loadCacheData( ep ) )
|
||||
return ep->sceneData;
|
||||
|
||||
ep->sceneData = m_Plugins->Load3DModel( aFileName, ep->pluginInfo );
|
||||
|
||||
if( !ADVANCED_CFG::GetCfg().m_Skip3DModelFileCache && nullptr != ep->sceneData )
|
||||
saveCacheData( ep );
|
||||
|
||||
return ep->sceneData;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::getSHA1( const wxString& aFileName, unsigned char* aSHA1Sum )
|
||||
{
|
||||
if( aFileName.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * [BUG] empty filename" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( nullptr == aSHA1Sum )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s\n * [BUG] NULL pointer passed for aMD5Sum" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FILE* fp = _wfopen( aFileName.wc_str(), L"rb" );
|
||||
#else
|
||||
FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
|
||||
#endif
|
||||
|
||||
if( nullptr == fp )
|
||||
return false;
|
||||
|
||||
boost::uuids::detail::sha1 dblock;
|
||||
unsigned char block[4096];
|
||||
size_t bsize = 0;
|
||||
|
||||
while( ( bsize = fread( &block, 1, 4096, fp ) ) > 0 )
|
||||
dblock.process_bytes( block, bsize );
|
||||
|
||||
fclose( fp );
|
||||
unsigned int digest[5];
|
||||
dblock.get_digest( digest );
|
||||
|
||||
// ensure MSB order
|
||||
for( int i = 0; i < 5; ++i )
|
||||
{
|
||||
int idx = i << 2;
|
||||
unsigned int tmp = digest[i];
|
||||
aSHA1Sum[idx+3] = tmp & 0xff;
|
||||
tmp >>= 8;
|
||||
aSHA1Sum[idx+2] = tmp & 0xff;
|
||||
tmp >>= 8;
|
||||
aSHA1Sum[idx+1] = tmp & 0xff;
|
||||
tmp >>= 8;
|
||||
aSHA1Sum[idx] = tmp & 0xff;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
|
||||
{
|
||||
wxString bname = aCacheItem->GetCacheBaseName();
|
||||
|
||||
if( bname.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_CacheDir.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( !wxFileName::FileExists( fname ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( " * [3D model] cannot open file '%s'" ), fname.GetData() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( nullptr != aCacheItem->sceneData )
|
||||
S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData );
|
||||
|
||||
aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag );
|
||||
|
||||
if( nullptr == aCacheItem->sceneData )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
|
||||
{
|
||||
if( nullptr == aCacheItem )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * NULL passed for aCacheItem" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( nullptr == aCacheItem->sceneData )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE, wxT( "%s:%s:%d\n * aCacheItem has no valid scene data" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString bname = aCacheItem->GetCacheBaseName();
|
||||
|
||||
if( bname.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; no file hash available" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_CacheDir.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] cannot load cached model; config directory unknown" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
|
||||
|
||||
if( wxFileName::Exists( fname ) )
|
||||
{
|
||||
if( !wxFileName::FileExists( fname ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( " * [3D model] path exists but is not a regular file '%s'" ), fname );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData,
|
||||
aCacheItem->pluginInfo.c_str() );
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
|
||||
{
|
||||
if( !m_ConfigDir.empty() )
|
||||
return false;
|
||||
|
||||
wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), wxEmptyString );
|
||||
|
||||
cfgdir.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
if( !cfgdir.DirExists() )
|
||||
{
|
||||
cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
|
||||
|
||||
if( !cfgdir.DirExists() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_ConfigDir = cfgdir.GetPath();
|
||||
|
||||
// inform the file resolver of the config directory
|
||||
if( !m_FNResolver->Set3DConfigDir( m_ConfigDir ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
|
||||
" * config directory: '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, m_ConfigDir );
|
||||
}
|
||||
|
||||
// 3D cache data must go to a user's cache directory;
|
||||
// unfortunately wxWidgets doesn't seem to provide
|
||||
// functions to retrieve such a directory.
|
||||
//
|
||||
// 1. OSX: ~/Library/Caches/kicad/3d/
|
||||
// 2. Linux: ${XDG_CACHE_HOME}/kicad/3d ~/.cache/kicad/3d/
|
||||
// 3. MSWin: AppData\Local\kicad\3d
|
||||
wxFileName cacheDir;
|
||||
cacheDir.AssignDir( PATHS::GetUserCachePath() );
|
||||
cacheDir.AppendDir( wxT( "3d" ) );
|
||||
|
||||
if( !cacheDir.DirExists() )
|
||||
{
|
||||
cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
|
||||
|
||||
if( !cacheDir.DirExists() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_CacheDir = cacheDir.GetPathWithSep();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D_CACHE::SetProject( PROJECT* aProject )
|
||||
{
|
||||
m_project = aProject;
|
||||
|
||||
bool hasChanged = false;
|
||||
|
||||
if( m_FNResolver->SetProject( aProject, &hasChanged ) && hasChanged )
|
||||
{
|
||||
m_CacheMap.clear();
|
||||
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator sL = m_CacheList.begin();
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator eL = m_CacheList.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
delete *sL;
|
||||
++sL;
|
||||
}
|
||||
|
||||
m_CacheList.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::SetProgramBase( PGM_BASE* aBase )
|
||||
{
|
||||
m_FNResolver->SetProgramBase( aBase );
|
||||
}
|
||||
|
||||
|
||||
FILENAME_RESOLVER* S3D_CACHE::GetResolver() noexcept
|
||||
{
|
||||
return m_FNResolver;
|
||||
}
|
||||
|
||||
|
||||
std::list< wxString > const* S3D_CACHE::GetFileFilters() const
|
||||
{
|
||||
return m_Plugins->GetFileFilters();
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::FlushCache( bool closePlugins )
|
||||
{
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator sCL = m_CacheList.begin();
|
||||
std::list< S3D_CACHE_ENTRY* >::iterator eCL = m_CacheList.end();
|
||||
|
||||
while( sCL != eCL )
|
||||
{
|
||||
delete *sCL;
|
||||
++sCL;
|
||||
}
|
||||
|
||||
m_CacheList.clear();
|
||||
m_CacheMap.clear();
|
||||
|
||||
if( closePlugins )
|
||||
ClosePlugins();
|
||||
}
|
||||
|
||||
|
||||
void S3D_CACHE::ClosePlugins()
|
||||
{
|
||||
if( m_Plugins )
|
||||
m_Plugins->ClosePlugins();
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& aBasePath )
|
||||
{
|
||||
S3D_CACHE_ENTRY* cp = nullptr;
|
||||
SCENEGRAPH* sp = load( aModelFileName, aBasePath,&cp );
|
||||
|
||||
if( !sp )
|
||||
return nullptr;
|
||||
|
||||
if( !cp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_CACHE,
|
||||
wxT( "%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( cp->renderData )
|
||||
return cp->renderData;
|
||||
|
||||
S3DMODEL* mp = S3D::GetModel( sp );
|
||||
cp->renderData = mp;
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
void S3D_CACHE::CleanCacheDir( int aNumDaysOld )
|
||||
{
|
||||
wxDir dir;
|
||||
wxString fileSpec = wxT( "*.3dc" );
|
||||
wxArrayString fileList; // Holds list of ".3dc" files found in cache directory
|
||||
size_t numFilesFound = 0;
|
||||
|
||||
wxFileName thisFile;
|
||||
wxDateTime lastAccess, thresholdDate;
|
||||
wxDateSpan durationInDays;
|
||||
|
||||
// Calc the threshold date above which we delete cache files
|
||||
durationInDays.SetDays( aNumDaysOld );
|
||||
thresholdDate = wxDateTime::Now() - durationInDays;
|
||||
|
||||
// If the cache directory can be found and opened, then we'll try and clean it up
|
||||
if( dir.Open( m_CacheDir ) )
|
||||
{
|
||||
thisFile.SetPath( m_CacheDir ); // Set the base path to the cache folder
|
||||
|
||||
// Get a list of all the ".3dc" files in the cache directory
|
||||
numFilesFound = dir.GetAllFiles( m_CacheDir, &fileList, fileSpec );
|
||||
|
||||
for( unsigned int i = 0; i < numFilesFound; i++ )
|
||||
{
|
||||
// Completes path to specific file so we can get its "last access" date
|
||||
thisFile.SetFullName( fileList[i] );
|
||||
|
||||
// Only get "last access" time to compare against. Don't need the other 2 timestamps.
|
||||
if( thisFile.GetTimes( &lastAccess, nullptr, nullptr ) )
|
||||
{
|
||||
if( lastAccess.IsEarlierThan( thresholdDate ) )
|
||||
{
|
||||
// This file is older than the threshold so delete it
|
||||
wxRemoveFile( thisFile.GetFullPath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PROJECT::Cleanup3DCache()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mutex3D_cacheManager );
|
||||
|
||||
// Get the existing cache from the project
|
||||
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( GetElem( ELEM_3DCACHE ) );
|
||||
|
||||
if( cache )
|
||||
{
|
||||
// We'll delete ".3dc" cache files older than this many days
|
||||
int clearCacheInterval = 0;
|
||||
|
||||
if( Pgm().GetCommonSettings() )
|
||||
clearCacheInterval = Pgm().GetCommonSettings()->m_System.clear_3d_cache_interval;
|
||||
|
||||
// An interval of zero means the user doesn't want to ever clear the cache
|
||||
|
||||
if( clearCacheInterval > 0 )
|
||||
cache->CleanCacheDir( clearCacheInterval );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S3D_CACHE* PROJECT::Get3DCacheManager( bool aUpdateProjDir )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mutex3D_cacheManager );
|
||||
|
||||
// Get the existing cache from the project
|
||||
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( GetElem( ELEM_3DCACHE ) );
|
||||
|
||||
if( !cache )
|
||||
{
|
||||
// Create a cache if there is not one already
|
||||
cache = new S3D_CACHE();
|
||||
|
||||
wxFileName cfgpath;
|
||||
cfgpath.AssignDir( SETTINGS_MANAGER::GetUserSettingsPath() );
|
||||
cfgpath.AppendDir( wxT( "3d" ) );
|
||||
|
||||
cache->SetProgramBase( &Pgm() );
|
||||
cache->Set3DConfigDir( cfgpath.GetFullPath() );
|
||||
|
||||
SetElem( ELEM_3DCACHE, cache );
|
||||
aUpdateProjDir = true;
|
||||
}
|
||||
|
||||
if( aUpdateProjDir )
|
||||
cache->SetProject( this );
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
FILENAME_RESOLVER* PROJECT::Get3DFilenameResolver()
|
||||
{
|
||||
return Get3DCacheManager()->GetResolver();
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_cache.h
|
||||
*/
|
||||
|
||||
#ifndef CACHE_3D_H
|
||||
#define CACHE_3D_H
|
||||
|
||||
#include "3d_info.h"
|
||||
#include <core/typeinfo.h>
|
||||
#include "string_utils.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
#include <project.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
class PGM_BASE;
|
||||
class S3D_CACHE_ENTRY;
|
||||
class SCENEGRAPH;
|
||||
class FILENAME_RESOLVER;
|
||||
class S3D_PLUGIN_MANAGER;
|
||||
|
||||
|
||||
/**
|
||||
* Cache for storing the 3D shapes. This cache is able to be stored as a project
|
||||
* element (since it inherits from PROJECT::_ELEM).
|
||||
*/
|
||||
class S3D_CACHE : public PROJECT::_ELEM
|
||||
{
|
||||
public:
|
||||
S3D_CACHE();
|
||||
virtual ~S3D_CACHE();
|
||||
|
||||
KICAD_T Type() noexcept override
|
||||
{
|
||||
return S3D_CACHE_T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration directory to be used by the model manager for storing 3D
|
||||
* model manager configuration data and the model cache.
|
||||
*
|
||||
* The config directory may only be set once in the lifetime of the object.
|
||||
*
|
||||
* @param aConfigDir is the configuration directory to use for 3D model manager data
|
||||
* @return true on success
|
||||
*/
|
||||
bool Set3DConfigDir( const wxString& aConfigDir );
|
||||
|
||||
/**
|
||||
* Set the current project's working directory; this affects the model search path.
|
||||
*/
|
||||
bool SetProject( PROJECT* aProject );
|
||||
|
||||
/**
|
||||
* Set the filename resolver's pointer to the application's PGM_BASE instance.
|
||||
*
|
||||
* The pointer is used to extract the local environment variables.
|
||||
*/
|
||||
void SetProgramBase( PGM_BASE* aBase );
|
||||
|
||||
/**
|
||||
* Attempt to load the scene data for a model.
|
||||
*
|
||||
* It will consult the internal cache list and load from cache if possible before invoking
|
||||
* the load() function of the available plugins. The model may fail to load if, for example,
|
||||
* the plugin does not support rendering of the 3D model.
|
||||
|
||||
*
|
||||
* @param aModelFile is the partial or full path to the model to be loaded.
|
||||
* @param aBasePath is the path to search for any relative files
|
||||
* @return true if the model was successfully loaded, otherwise false.
|
||||
*/
|
||||
SCENEGRAPH* Load( const wxString& aModelFile, const wxString& aBasePath );
|
||||
|
||||
FILENAME_RESOLVER* GetResolver() noexcept;
|
||||
|
||||
/**
|
||||
* Return the list of file filters retrieved from the plugins.
|
||||
*
|
||||
* This will contain at least the default "All Files (*.*)|*.*"
|
||||
*
|
||||
* @return a pointer to the filter list.
|
||||
*/
|
||||
std::list< wxString > const* GetFileFilters() const;
|
||||
|
||||
/**
|
||||
* Free all data in the cache and by default closes all plugins.
|
||||
*/
|
||||
void FlushCache( bool closePlugins = true );
|
||||
|
||||
/**
|
||||
* Unload plugins to free memory.
|
||||
*/
|
||||
void ClosePlugins();
|
||||
|
||||
/**
|
||||
* Attempt to load the scene data for a model and to translate it into an S3D_MODEL
|
||||
* structure for display by a renderer.
|
||||
*
|
||||
* @param aModelFileName is the full path to the model to be loaded.
|
||||
* @return is a pointer to the render data or NULL if not available.
|
||||
*/
|
||||
S3DMODEL* GetModel( const wxString& aModelFileName, const wxString& aBasePath );
|
||||
|
||||
/**
|
||||
* Delete up old cache files in cache directory.
|
||||
*
|
||||
* Deletes ".3dc" files in the cache directory that are older than \a aNumDaysOld.
|
||||
*
|
||||
* @param aNumDaysOld is age threshold to delete ".3dc" cache files.
|
||||
*/
|
||||
void CleanCacheDir( int aNumDaysOld );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Find or create cache entry for file name
|
||||
*
|
||||
* Searches the cache list for the given filename and retrieves the cache data; a cache
|
||||
* entry is created if one does not already exist.
|
||||
*
|
||||
* @param aFileName is the file name (full or partial path).
|
||||
* @param aCachePtr is an optional return address for cache entry pointer.
|
||||
* @return SCENEGRAPH object associated with file name or NULL on error.
|
||||
*/
|
||||
SCENEGRAPH* checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr = nullptr );
|
||||
|
||||
/**
|
||||
* Calculate the SHA1 hash of the given file.
|
||||
*
|
||||
* @param aFileName file name (full path).
|
||||
* @param aSHA1Sum a 20 byte character array to hold the SHA1 hash.
|
||||
* @return true on success, otherwise false.
|
||||
*/
|
||||
bool getSHA1( const wxString& aFileName, unsigned char* aSHA1Sum );
|
||||
|
||||
// load scene data from a cache file
|
||||
bool loadCacheData( S3D_CACHE_ENTRY* aCacheItem );
|
||||
|
||||
// save scene data to a cache file
|
||||
bool saveCacheData( S3D_CACHE_ENTRY* aCacheItem );
|
||||
|
||||
// the real load function (can supply a cache entry pointer to member functions)
|
||||
SCENEGRAPH* load( const wxString& aModelFile, const wxString& aBasePath, S3D_CACHE_ENTRY** aCachePtr = nullptr );
|
||||
|
||||
/// cache entries
|
||||
std::list< S3D_CACHE_ENTRY* > m_CacheList;
|
||||
|
||||
/// mapping of file names to cache names and data
|
||||
std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString > m_CacheMap;
|
||||
|
||||
FILENAME_RESOLVER* m_FNResolver;
|
||||
|
||||
S3D_PLUGIN_MANAGER* m_Plugins;
|
||||
|
||||
PROJECT* m_project;
|
||||
wxString m_CacheDir;
|
||||
wxString m_ConfigDir; /// base configuration path for 3D items
|
||||
};
|
||||
|
||||
#endif // CACHE_3D_H
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_info.h
|
||||
* defines the basic data associated with a single 3D model.
|
||||
*/
|
||||
|
||||
#ifndef INFO_3D_H
|
||||
#define INFO_3D_H
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <plugins/3dapi/sg_base.h>
|
||||
|
||||
class FP_3DMODEL;
|
||||
|
||||
struct S3D_INFO
|
||||
{
|
||||
S3D_INFO();
|
||||
S3D_INFO( const FP_3DMODEL& aModel );
|
||||
|
||||
SGPOINT m_Scale; ///< scaling factors for the 3D footprint shape
|
||||
SGPOINT m_Rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
|
||||
SGPOINT m_Offset; ///< an offset (unit = inch) for the 3D shape
|
||||
wxString m_Filename; ///< The 3D shape filename in 3D library
|
||||
};
|
||||
|
||||
#endif // INFO_3D_H
|
||||
@@ -1,501 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <wx/dir.h>
|
||||
#include <wx/dynlib.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <paths.h>
|
||||
#include <wx_filename.h>
|
||||
#include "3d_plugin_manager.h"
|
||||
#include "plugins/3d/3d_plugin.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "plugins/ldr/3d/pluginldr3D.h"
|
||||
|
||||
|
||||
/**
|
||||
* Flag to enable 3D plugin manager debug tracing.
|
||||
*
|
||||
* Use "KI_TRACE_EDA_3D_VIEWER" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
#define MASK_3D_PLUGINMGR "3D_PLUGIN_MANAGER"
|
||||
|
||||
|
||||
S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
|
||||
{
|
||||
// create the initial file filter list entry
|
||||
m_FileFilters.emplace_back( _( "All Files" ) + wxT( " (*.*)|*.*" ) );
|
||||
|
||||
// discover and load plugins
|
||||
loadPlugins();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !m_ExtMap.empty() )
|
||||
{
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator sM = m_ExtMap.begin();
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator eM = m_ExtMap.end();
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * Extension [plugin name]:\n" ) );
|
||||
|
||||
while( sM != eM )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s' [%s]\n" ), sM->first.GetData(),
|
||||
sM->second->GetKicadPluginName() );
|
||||
++sM;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No plugins available\n" ) );
|
||||
}
|
||||
|
||||
|
||||
if( !m_FileFilters.empty() )
|
||||
{
|
||||
/// list of file filters
|
||||
std::list< wxString >::const_iterator sFF = m_FileFilters.begin();
|
||||
std::list< wxString >::const_iterator eFF = m_FileFilters.end();
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * File filters:\n" ) );
|
||||
|
||||
while( sFF != eFF )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " + '%s'\n" ), (*sFF).GetData() );
|
||||
++sFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * No file filters available\n" ) );
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
|
||||
S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
|
||||
{
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
|
||||
|
||||
while( sP != eP )
|
||||
{
|
||||
(*sP)->Close();
|
||||
delete *sP;
|
||||
++sP;
|
||||
}
|
||||
|
||||
m_Plugins.clear();
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::loadPlugins( void )
|
||||
{
|
||||
std::list<wxString> searchpaths;
|
||||
std::list<wxString> pluginlist;
|
||||
wxFileName fn;
|
||||
|
||||
#ifndef __WXMAC__
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
// set up to work from the build directory
|
||||
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
|
||||
fn.AppendDir( wxT( ".." ) );
|
||||
fn.AppendDir( wxT( "plugins" ) );
|
||||
fn.AppendDir( wxT( "3d" ) );
|
||||
|
||||
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
|
||||
checkPluginPath( testpath, searchpaths );
|
||||
|
||||
// add subdirectories too
|
||||
wxDir debugPluginDir;
|
||||
wxString subdir;
|
||||
|
||||
debugPluginDir.Open( testpath );
|
||||
|
||||
if( debugPluginDir.IsOpened()
|
||||
&& debugPluginDir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS ) )
|
||||
{
|
||||
checkPluginPath( testpath + subdir, searchpaths );
|
||||
|
||||
while( debugPluginDir.GetNext( &subdir ) )
|
||||
checkPluginPath( testpath + subdir, searchpaths );
|
||||
}
|
||||
}
|
||||
|
||||
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
|
||||
checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
|
||||
#else
|
||||
// Search path on OS X is
|
||||
// (1) Machine /Library/Application Support/kicad/PlugIns/3d
|
||||
checkPluginPath( PATHS::GetOSXKicadMachineDataDir() + wxT( "/PlugIns/3d" ), searchpaths );
|
||||
|
||||
// (2) Bundle kicad.app/Contents/PlugIns/3d
|
||||
fn.AssignDir( PATHS::GetStockPlugins3DPath() );
|
||||
checkPluginPath( fn.GetPathWithSep(), searchpaths );
|
||||
#endif
|
||||
|
||||
std::list< wxString >::iterator sPL = searchpaths.begin();
|
||||
std::list< wxString >::iterator ePL = searchpaths.end();
|
||||
|
||||
while( sPL != ePL )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] searching path: '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, (*sPL).ToUTF8() );
|
||||
|
||||
listPlugins( *sPL, pluginlist );
|
||||
++sPL;
|
||||
}
|
||||
|
||||
if( pluginlist.empty() )
|
||||
return;
|
||||
|
||||
sPL = pluginlist.begin();
|
||||
ePL = pluginlist.end();
|
||||
|
||||
while( sPL != ePL )
|
||||
{
|
||||
KICAD_PLUGIN_LDR_3D* pp = new KICAD_PLUGIN_LDR_3D;
|
||||
|
||||
if( pp->Open( sPL->ToUTF8() ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding plugin" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
m_Plugins.push_back( pp );
|
||||
int nf = pp->GetNFilters();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] adding %d filters" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, nf );
|
||||
|
||||
for( int i = 0; i < nf; ++i )
|
||||
{
|
||||
char const* cp = pp->GetFileFilter( i );
|
||||
|
||||
if( cp )
|
||||
addFilterString( wxString::FromUTF8Unchecked( cp ) );
|
||||
}
|
||||
|
||||
addExtensionMap( pp );
|
||||
|
||||
// close the loaded library
|
||||
pp->Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] deleting plugin" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
delete pp;
|
||||
}
|
||||
|
||||
++sPL;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [DEBUG] plugins loaded" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath, std::list< wxString >& aPluginList )
|
||||
{
|
||||
// list potential plugins given a search path
|
||||
wxString nameFilter; // filter for user-loadable libraries (aka footprints)
|
||||
wxString lName; // stores name of enumerated files
|
||||
wxString fName; // full name of file
|
||||
wxDir wd;
|
||||
wd.Open( aPath );
|
||||
|
||||
if( !wd.IsOpened() )
|
||||
return;
|
||||
|
||||
nameFilter = wxT( "*" );
|
||||
|
||||
#ifndef __WXMAC__
|
||||
nameFilter.Append( wxDynamicLibrary::GetDllExt( wxDL_MODULE ) );
|
||||
#else
|
||||
// wxDynamicLibrary::GetDllExt( wxDL_MODULE ) will return ".bundle" on OS X.
|
||||
// This might be correct, but cmake builds a ".so" for a library MODULE.
|
||||
// Per definition a loadable "xxx.bundle" is similar to an "xxx.app" app
|
||||
// bundle being a folder with some special content in it. We obviously don't
|
||||
// want to have that here for our loadable module, so just use ".so".
|
||||
nameFilter.Append( wxS( ".so" ) );
|
||||
#endif
|
||||
|
||||
wxString lp = wd.GetNameWithSep();
|
||||
|
||||
if( wd.GetFirst( &lName, nameFilter, wxDIR_FILES ) )
|
||||
{
|
||||
fName = lp + lName;
|
||||
checkPluginName( fName, aPluginList );
|
||||
|
||||
while( wd.GetNext( &lName ) )
|
||||
{
|
||||
fName = lp + lName;
|
||||
checkPluginName( fName, aPluginList );
|
||||
}
|
||||
}
|
||||
|
||||
wd.Close();
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
|
||||
std::list< wxString >& aPluginList )
|
||||
{
|
||||
// check the existence of a plugin name and add it to the list
|
||||
|
||||
if( aPath.empty() || !wxFileName::FileExists( aPath ) )
|
||||
return;
|
||||
|
||||
wxFileName path( ExpandEnvVarSubstitutions( aPath, nullptr ) );
|
||||
|
||||
path.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
// determine if the path is already in the list
|
||||
wxString wxpath = path.GetFullPath();
|
||||
std::list< wxString >::iterator bl = aPluginList.begin();
|
||||
std::list< wxString >::iterator el = aPluginList.end();
|
||||
|
||||
while( bl != el )
|
||||
{
|
||||
if( 0 == (*bl).Cmp( wxpath ) )
|
||||
return;
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
// prevent loading non-plugin dlls
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
if( !path.GetName().StartsWith( "s3d_plugin" )
|
||||
&& !path.GetName().StartsWith( "libs3d_plugin" ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aPluginList.push_back( wxpath );
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] found 3D plugin '%s'\n" ), wxpath.GetData() );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
|
||||
std::list< wxString >& aSearchList )
|
||||
{
|
||||
if( aPath.empty() )
|
||||
return;
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( " * [INFO] checking if valid plugin directory '%s'\n" ),
|
||||
aPath.GetData() );
|
||||
|
||||
wxFileName path;
|
||||
path.AssignDir( aPath );
|
||||
path.Normalize( FN_NORMALIZE_FLAGS );
|
||||
|
||||
if( !wxFileName::DirExists( path.GetFullPath() ) )
|
||||
return;
|
||||
|
||||
// determine if the directory is already in the list
|
||||
wxString wxpath = path.GetFullPath();
|
||||
std::list< wxString >::iterator bl = aSearchList.begin();
|
||||
std::list< wxString >::iterator el = aSearchList.end();
|
||||
|
||||
while( bl != el )
|
||||
{
|
||||
if( 0 == (*bl).Cmp( wxpath ) )
|
||||
return;
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
aSearchList.push_back( wxpath );
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
|
||||
{
|
||||
// add an entry to the file filter list
|
||||
if( aFilterString.empty() )
|
||||
return;
|
||||
|
||||
std::list< wxString >::iterator sFF = m_FileFilters.begin();
|
||||
std::list< wxString >::iterator eFF = m_FileFilters.end();
|
||||
|
||||
while( sFF != eFF )
|
||||
{
|
||||
if( 0 == (*sFF).Cmp( aFilterString ) )
|
||||
return;
|
||||
|
||||
++sFF;
|
||||
}
|
||||
|
||||
m_FileFilters.push_back( aFilterString );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
|
||||
{
|
||||
// add entries to the extension map
|
||||
if( nullptr == aPlugin )
|
||||
return;
|
||||
|
||||
int nExt = aPlugin->GetNExtensions();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] adding %d extensions" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, nExt );
|
||||
|
||||
for( int i = 0; i < nExt; ++i )
|
||||
{
|
||||
char const* cp = aPlugin->GetModelExtension( i );
|
||||
wxString ws;
|
||||
|
||||
if( cp )
|
||||
ws = wxString::FromUTF8Unchecked( cp );
|
||||
|
||||
if( !ws.empty() )
|
||||
{
|
||||
m_ExtMap.emplace( ws, aPlugin );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const noexcept
|
||||
{
|
||||
return &m_FileFilters;
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo )
|
||||
{
|
||||
wxFileName raw( aFileName );
|
||||
wxString ext_to_find = raw.GetExt();
|
||||
|
||||
#ifdef _WIN32
|
||||
// note: plugins only have a lowercase filter within Windows; including an uppercase
|
||||
// filter will result in duplicate file entries and should be avoided.
|
||||
ext_to_find.MakeLower();
|
||||
#endif
|
||||
|
||||
// .gz files are compressed versions that may have additional information in the previous extension
|
||||
if( ext_to_find == wxT( "gz" ) )
|
||||
{
|
||||
wxFileName second( raw.GetName() );
|
||||
ext_to_find = second.GetExt() + wxT( ".gz" );
|
||||
}
|
||||
|
||||
std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator,
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items;
|
||||
|
||||
items = m_ExtMap.equal_range( ext_to_find );
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
|
||||
|
||||
while( sL != items.second )
|
||||
{
|
||||
if( sL->second->CanRender() )
|
||||
{
|
||||
SCENEGRAPH* sp = sL->second->Load( aFileName.ToUTF8() );
|
||||
|
||||
if( nullptr != sp )
|
||||
{
|
||||
sL->second->GetPluginInfo( aPluginInfo );
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
|
||||
++sL;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void S3D_PLUGIN_MANAGER::ClosePlugins( void )
|
||||
{
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
|
||||
|
||||
wxLogTrace( MASK_3D_PLUGINMGR, wxT( "%s:%s:%d * [INFO] closing %d extensions" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, static_cast<int>( m_Plugins.size() ) );
|
||||
|
||||
while( sP != eP )
|
||||
{
|
||||
(*sP)->Close();
|
||||
++sP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool S3D_PLUGIN_MANAGER::CheckTag( const char* aTag )
|
||||
{
|
||||
if( nullptr == aTag || aTag[0] == 0 || m_Plugins.empty() )
|
||||
return false;
|
||||
|
||||
std::string tname = aTag;
|
||||
std::string pname; // plugin name
|
||||
|
||||
size_t cpos = tname.find( ':' );
|
||||
|
||||
// if there is no colon or plugin name then the tag is bad
|
||||
if( cpos == std::string::npos || cpos == 0 )
|
||||
return false;
|
||||
|
||||
pname = tname.substr( 0, cpos );
|
||||
std::string ptag; // tag from the plugin
|
||||
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pS = m_Plugins.begin();
|
||||
std::list< KICAD_PLUGIN_LDR_3D* >::iterator pE = m_Plugins.end();
|
||||
|
||||
while( pS != pE )
|
||||
{
|
||||
ptag.clear();
|
||||
(*pS)->GetPluginInfo( ptag );
|
||||
|
||||
// if the plugin name matches then the version
|
||||
// must also match
|
||||
if( !ptag.compare( 0, pname.size(), pname ) )
|
||||
{
|
||||
if( ptag.compare( tname ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
++pS;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_plugin_manager.h
|
||||
* manages 3D model plugins
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_MANAGER_3D_H
|
||||
#define PLUGIN_MANAGER_3D_H
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxWindow;
|
||||
class KICAD_PLUGIN_LDR_3D;
|
||||
class SCENEGRAPH;
|
||||
|
||||
class S3D_PLUGIN_MANAGER
|
||||
{
|
||||
public:
|
||||
S3D_PLUGIN_MANAGER();
|
||||
virtual ~S3D_PLUGIN_MANAGER();
|
||||
|
||||
/**
|
||||
* Return the list of file filters; this will contain at least the default
|
||||
* "All Files (*.*)|*.*" and the file filters supported by any available plugins.
|
||||
*
|
||||
* @return a pointer to the internal filter list.
|
||||
*/
|
||||
std::list< wxString > const* GetFileFilters( void ) const noexcept;
|
||||
|
||||
SCENEGRAPH* Load3DModel( const wxString& aFileName, std::string& aPluginInfo );
|
||||
|
||||
/**
|
||||
* Iterate through all discovered plugins and closes them to reclaim memory.
|
||||
*
|
||||
* The individual plugins will be automatically reloaded as calls are made to load
|
||||
* specific models.
|
||||
*/
|
||||
void ClosePlugins( void );
|
||||
|
||||
/**
|
||||
* Check the given tag and returns true if the plugin named in the tag is not loaded
|
||||
* or the plugin is loaded and the version matches.
|
||||
*/
|
||||
bool CheckTag( const char* aTag );
|
||||
|
||||
private:
|
||||
/// load plugins
|
||||
void loadPlugins( void );
|
||||
|
||||
/// list potential plugins
|
||||
void listPlugins( const wxString& aPath, std::list< wxString >& aPluginList );
|
||||
|
||||
/// check the existence of a plugin name and add it to the list
|
||||
void checkPluginName( const wxString& aPath, std::list< wxString >& aPluginList );
|
||||
|
||||
/// check the existence of a path and add it to the path search list
|
||||
void checkPluginPath( const wxString& aPath, std::list< wxString >& aSearchList );
|
||||
|
||||
/// add an entry to the file filter list
|
||||
void addFilterString( const wxString& aFilterString );
|
||||
|
||||
/// add entries to the extension map
|
||||
void addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin );
|
||||
|
||||
/// list of discovered plugins
|
||||
std::list< KICAD_PLUGIN_LDR_3D* > m_Plugins;
|
||||
|
||||
/// mapping of extensions to available plugins
|
||||
std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* > m_ExtMap;
|
||||
|
||||
/// list of file filters
|
||||
std::list< wxString > m_FileFilters;
|
||||
};
|
||||
|
||||
#endif // PLUGIN_MANAGER_3D_H
|
||||
@@ -1 +0,0 @@
|
||||
add_subdirectory( sg )
|
||||
@@ -1,111 +0,0 @@
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/3d-viewer
|
||||
)
|
||||
|
||||
set( SG_FILES
|
||||
sg_base.cpp
|
||||
sg_node.cpp
|
||||
sg_helpers.cpp
|
||||
scenegraph.cpp
|
||||
sg_appearance.cpp
|
||||
sg_faceset.cpp
|
||||
sg_shape.cpp
|
||||
sg_colors.cpp
|
||||
sg_coords.cpp
|
||||
sg_normals.cpp
|
||||
sg_index.cpp
|
||||
sg_coordindex.cpp
|
||||
ifsg_node.cpp
|
||||
ifsg_transform.cpp
|
||||
ifsg_appearance.cpp
|
||||
ifsg_index.cpp
|
||||
ifsg_coordindex.cpp
|
||||
ifsg_colors.cpp
|
||||
ifsg_coords.cpp
|
||||
ifsg_faceset.cpp
|
||||
ifsg_normals.cpp
|
||||
ifsg_shape.cpp
|
||||
ifsg_api.cpp
|
||||
)
|
||||
|
||||
if( MINGW )
|
||||
list( APPEND SG_FILES ${CMAKE_SOURCE_DIR}/common/streamwrapper.cpp )
|
||||
endif( MINGW )
|
||||
|
||||
add_library( kicad_3dsg SHARED ${SG_FILES} )
|
||||
|
||||
if( APPLE )
|
||||
# puts library into the main kicad.app bundle in build tree
|
||||
set_target_properties( kicad_3dsg PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
INSTALL_NAME_DIR "${OSX_BUNDLE_BUILD_LIB_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
find_file( S3DSG_VERSION_FILE sg_version.h
|
||||
PATHS ${CMAKE_SOURCE_DIR}/include/plugins/3dapi NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
|
||||
if( NOT ${S3DSG_VERSION_FILE} STREQUAL "S3DSG_VERSION_FILE-NOTFOUND" )
|
||||
|
||||
# extract the "#define KICADSG_VERSION_*" lines
|
||||
file( STRINGS ${S3DSG_VERSION_FILE} _version
|
||||
REGEX "^[' ','\t']*#define[' ','\t']*KICADSG_VERSION_.*" )
|
||||
|
||||
foreach( SVAR ${_version} )
|
||||
string( REGEX MATCH KICADSG_VERSION_[M,A,J,O,R,I,N,P,T,C,H,E,V]* _VARNAME ${SVAR} )
|
||||
string( REGEX MATCH [0-9]+ _VALUE ${SVAR} )
|
||||
|
||||
if( NOT ${_VARNAME} STREQUAL "" )
|
||||
if( NOT ${_VALUE} STREQUAL "" )
|
||||
set( ${_VARNAME} ${_VALUE} )
|
||||
else()
|
||||
set( ${_VARNAME} 0 )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
if( NOT KICADSG_VERSION_MAJOR AND NOT ${KICADSG_VERSION_MAJOR} STREQUAL "0" )
|
||||
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
|
||||
endif()
|
||||
|
||||
#ensure that NOT SG_VERSION* will evaluate to '0'
|
||||
if( NOT KICADSG_VERSION_MINOR )
|
||||
set( KICADSG_VERSION_MINOR 0 )
|
||||
endif()
|
||||
|
||||
if( NOT KICADSG_VERSION_PATCH )
|
||||
set( KICADSG_VERSION_PATCH 0 )
|
||||
endif()
|
||||
|
||||
set_target_properties( kicad_3dsg
|
||||
PROPERTIES SOVERSION
|
||||
${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH} )
|
||||
|
||||
message( STATUS "S3DSG version: ${KICADSG_VERSION_MAJOR}.${KICADSG_VERSION_MINOR}.${KICADSG_VERSION_PATCH}" )
|
||||
else()
|
||||
message( FATAL_ERROR "Cannot determine the S3DSG library version" )
|
||||
endif()
|
||||
|
||||
unset( S3DSG_VERSION_FILE CACHE )
|
||||
|
||||
# Define a flag to expose the appropriate EXPORT macro at build time
|
||||
target_compile_definitions( kicad_3dsg PRIVATE -DCOMPILE_SGLIB )
|
||||
|
||||
target_link_libraries( kicad_3dsg ${wxWidgets_LIBRARIES} )
|
||||
|
||||
# Don't specify the ARCHIVE DESTINATION parameter to prevent
|
||||
# the install of the import library on Windows
|
||||
# https://cmake.org/pipermail/cmake/2011-November/047746.html
|
||||
install( TARGETS
|
||||
kicad_3dsg
|
||||
RUNTIME DESTINATION ${KICAD_LIB}
|
||||
LIBRARY DESTINATION ${KICAD_LIB}
|
||||
COMPONENT binary
|
||||
)
|
||||
|
||||
if( KICAD_WIN32_INSTALL_PDBS )
|
||||
# Get the PDBs to copy over for MSVC
|
||||
install(FILES $<TARGET_PDB_FILE:kicad_3dsg> DESTINATION ${KICAD_BIN})
|
||||
endif()
|
||||
@@ -1,527 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/log.h>
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
#include "plugins/3dapi/sg_version.h"
|
||||
#include "streamwrapper.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
// version format of the cache file
|
||||
#define SG_VERSION_TAG "VERSION:2"
|
||||
|
||||
|
||||
static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
|
||||
{
|
||||
float v0, v1, v2;
|
||||
|
||||
app->ambient.GetColor( v0, v1, v2 );
|
||||
mat.m_Ambient.x = v0;
|
||||
mat.m_Ambient.y = v1;
|
||||
mat.m_Ambient.z = v2;
|
||||
|
||||
app->diffuse.GetColor( v0, v1, v2 );
|
||||
mat.m_Diffuse.x = v0;
|
||||
mat.m_Diffuse.y = v1;
|
||||
mat.m_Diffuse.z = v2;
|
||||
mat.m_Ambient.x *= v0;
|
||||
mat.m_Ambient.y *= v1;
|
||||
mat.m_Ambient.z *= v2;
|
||||
|
||||
app->emissive.GetColor( v0, v1, v2 );
|
||||
mat.m_Emissive.x = v0;
|
||||
mat.m_Emissive.y = v1;
|
||||
mat.m_Emissive.z = v2;
|
||||
|
||||
app->specular.GetColor( v0, v1, v2 );
|
||||
mat.m_Specular.x = v0;
|
||||
mat.m_Specular.y = v1;
|
||||
mat.m_Specular.z = v2;
|
||||
|
||||
mat.m_Shininess = app->shininess;
|
||||
mat.m_Transparency = app->transparency;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
|
||||
bool reuse, bool renameNodes )
|
||||
{
|
||||
if( nullptr == filename || filename[0] == 0 )
|
||||
return false;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( filename );
|
||||
|
||||
if( wxFileName::Exists( ofile ) )
|
||||
{
|
||||
if( !overwrite )
|
||||
return false;
|
||||
|
||||
// make sure we make no attempt to write a directory
|
||||
if( !wxFileName::FileExists( ofile ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( aTopNode && aTopNode->GetNodeType() == S3D::SGTYPE_TRANSFORM, false );
|
||||
|
||||
OPEN_OSTREAM( op, filename );
|
||||
|
||||
if( op.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, filename );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
op.imbue( std::locale::classic() );
|
||||
op << "#VRML V2.0 utf8\n";
|
||||
|
||||
if( renameNodes )
|
||||
{
|
||||
aTopNode->ResetNodeIndex();
|
||||
aTopNode->ReNameNodes();
|
||||
}
|
||||
|
||||
aTopNode->WriteVRML( op, reuse );
|
||||
|
||||
if( !op.fail() )
|
||||
{
|
||||
CLOSE_STREAM( op );
|
||||
return true;
|
||||
}
|
||||
|
||||
CLOSE_STREAM( op );
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered writing file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, filename );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D::ResetNodeIndex( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
aNode->ResetNodeIndex();
|
||||
}
|
||||
|
||||
|
||||
void S3D::RenameNodes( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
aNode->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
void S3D::DestroyNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, /* void */ );
|
||||
|
||||
delete aNode;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
|
||||
const char* aPluginInfo )
|
||||
{
|
||||
if( nullptr == aFileName || aFileName[0] == 0 )
|
||||
return false;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
|
||||
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
if( wxFileName::Exists( ofile ) )
|
||||
{
|
||||
if( !overwrite )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] file exists not overwriting '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we make no attempt to write a directory
|
||||
if( !wxFileName::FileExists( aFileName ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] specified path is a directory '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
OPEN_OSTREAM( output, aFileName );
|
||||
|
||||
if( output.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
output << "(" << SG_VERSION_TAG << ")";
|
||||
|
||||
if( nullptr != aPluginInfo && aPluginInfo[0] != 0 )
|
||||
output << "(" << aPluginInfo << ")";
|
||||
else
|
||||
output << "(INTERNAL:0.0.0.0)";
|
||||
|
||||
bool rval = aNode->WriteCache( output, nullptr );
|
||||
CLOSE_STREAM( output );
|
||||
|
||||
if( !rval )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] problems encountered writing cache file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
// delete the defective file
|
||||
wxRemoveFile( ofile );
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
|
||||
bool (*aTagCheck)( const char*, void* ) )
|
||||
{
|
||||
if( nullptr == aFileName || aFileName[0] == 0 )
|
||||
return nullptr;
|
||||
|
||||
wxString ofile = wxString::FromUTF8Unchecked( aFileName );
|
||||
|
||||
if( !wxFileName::FileExists( aFileName ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] no such file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SGNODE> np = std::make_unique<SCENEGRAPH>( nullptr );
|
||||
|
||||
OPEN_ISTREAM( file, aFileName );
|
||||
|
||||
if( file.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] failed to open file '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// from SG_VERSION_TAG 1, read the version tag; if it's not the expected tag
|
||||
// then we fail to read the cache file
|
||||
do
|
||||
{
|
||||
std::string name;
|
||||
char schar;
|
||||
file.get( schar );
|
||||
|
||||
if( '(' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
|
||||
" at position '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( file.tellg() ) );
|
||||
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.get( schar );
|
||||
|
||||
while( ')' != schar && file.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
file.get( schar );
|
||||
}
|
||||
|
||||
if( name.compare( SG_VERSION_TAG ) )
|
||||
{
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// from SG_VERSION_TAG 2, read the PluginInfo string and check that it matches
|
||||
// version tag; if it's not the expected tag then we fail to read the file
|
||||
do
|
||||
{
|
||||
std::string name;
|
||||
char schar;
|
||||
file.get( schar );
|
||||
|
||||
if( '(' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left parenthesis"
|
||||
" at position '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( file.tellg() ) );
|
||||
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.get( schar );
|
||||
|
||||
while( ')' != schar && file.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
file.get( schar );
|
||||
}
|
||||
|
||||
// check the plugin tag
|
||||
if( nullptr != aTagCheck && nullptr != aPluginMgr
|
||||
&& !aTagCheck( name.c_str(), aPluginMgr ) )
|
||||
{
|
||||
CLOSE_STREAM( file );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
bool rval = np->ReadCache( file, nullptr );
|
||||
CLOSE_STREAM( file );
|
||||
|
||||
if( !rval )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] problems encountered reading cache file "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aFileName );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return np.release();
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D::GetModel( SCENEGRAPH* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return nullptr;
|
||||
|
||||
if( aNode->GetNodeType() != S3D::SGTYPE_TRANSFORM )
|
||||
return nullptr;
|
||||
|
||||
S3D::MATLIST materials;
|
||||
std::vector< SMESH > meshes;
|
||||
|
||||
// the materials list shall have a default color; although the VRML
|
||||
// default is an opaque black, the default used here shall be a median
|
||||
// gray in hopes that it may help highlight faulty models; this color is
|
||||
// also typical of MCAD applications. When a model has no associated
|
||||
// material color it shall be assigned the index 0.
|
||||
SGAPPEARANCE app( nullptr );
|
||||
app.ambient = SGCOLOR( 0.6f, 0.6f, 0.6f );
|
||||
app.diffuse = SGCOLOR( 0.6f, 0.6f, 0.6f );
|
||||
app.specular = app.diffuse;
|
||||
app.shininess = 0.05f;
|
||||
app.transparency = 0.0f;
|
||||
|
||||
materials.matorder.push_back( &app );
|
||||
materials.matmap.emplace( &app, 0 );
|
||||
|
||||
if( aNode->Prepare( nullptr, materials, meshes ) )
|
||||
{
|
||||
if( meshes.empty() )
|
||||
return nullptr;
|
||||
|
||||
S3DMODEL* model = S3D::New3DModel();
|
||||
|
||||
// add all the materials
|
||||
size_t j = materials.matorder.size();
|
||||
SMATERIAL* lmat = new SMATERIAL[j];
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
formatMaterial( lmat[i], materials.matorder[i] );
|
||||
|
||||
model->m_Materials = lmat;
|
||||
model->m_MaterialsSize = j;
|
||||
|
||||
// add all the meshes
|
||||
j = meshes.size();
|
||||
SMESH* lmesh = new SMESH[j];
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
lmesh[i] = meshes[i];
|
||||
|
||||
model->m_Meshes = lmesh;
|
||||
model->m_MeshesSize = j;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
size_t j = meshes.size();
|
||||
|
||||
for( size_t i = 0; i < j; ++i )
|
||||
S3D::Free3DMesh( meshes[i] );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void S3D::Destroy3DModel( S3DMODEL** aModel )
|
||||
{
|
||||
if( nullptr == aModel || nullptr == *aModel )
|
||||
return;
|
||||
|
||||
S3DMODEL* m = *aModel;
|
||||
S3D::FREE_S3DMODEL( *m );
|
||||
delete m;
|
||||
*aModel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Free3DModel( S3DMODEL& aModel )
|
||||
{
|
||||
S3D::FREE_S3DMODEL( aModel );
|
||||
}
|
||||
|
||||
|
||||
void S3D::Free3DMesh( SMESH& aMesh )
|
||||
{
|
||||
S3D::FREE_SMESH( aMesh );
|
||||
}
|
||||
|
||||
|
||||
S3DMODEL* S3D::New3DModel( void )
|
||||
{
|
||||
S3DMODEL* mp = new S3DMODEL;
|
||||
S3D::INIT_S3DMODEL( *mp );
|
||||
return mp;
|
||||
}
|
||||
|
||||
|
||||
void S3D::Init3DMaterial( SMATERIAL& aMat )
|
||||
{
|
||||
S3D::INIT_SMATERIAL( aMat );
|
||||
}
|
||||
|
||||
|
||||
void S3D::Init3DMesh( SMESH& aMesh )
|
||||
{
|
||||
S3D::INIT_SMESH( aMesh );
|
||||
}
|
||||
|
||||
|
||||
void S3D::GetLibVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch,
|
||||
unsigned char* Revision ) noexcept
|
||||
{
|
||||
if( Major )
|
||||
*Major = KICADSG_VERSION_MAJOR;
|
||||
|
||||
if( Minor )
|
||||
*Minor = KICADSG_VERSION_MINOR;
|
||||
|
||||
if( Revision )
|
||||
*Revision = KICADSG_VERSION_REVISION;
|
||||
|
||||
if( Patch )
|
||||
*Patch = KICADSG_VERSION_PATCH;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR S3D::CalcTriNorm( const SGPOINT& p1, const SGPOINT& p2, const SGPOINT& p3 )
|
||||
{
|
||||
glm::dvec3 tri = glm::dvec3( 0.0, 0.0, 0.0 );
|
||||
glm::dvec3 pts[3];
|
||||
|
||||
pts[0] = glm::dvec3( p1.x, p1.y, p1.z );
|
||||
pts[1] = glm::dvec3( p2.x, p2.y, p2.z );
|
||||
pts[2] = glm::dvec3( p3.x, p3.y, p3.z );
|
||||
|
||||
// degenerate points are given a default 0, 0, 1 normal
|
||||
if( S3D::degenerate( pts ) )
|
||||
return SGVECTOR( 0.0, 0.0, 1.0 );
|
||||
|
||||
// normal
|
||||
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
|
||||
glm::normalize( tri );
|
||||
|
||||
return SGVECTOR( tri.x, tri.y, tri.z );
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES S3D::GetSGNodeType( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return SGTYPE_END;
|
||||
|
||||
return aNode->GetNodeType();
|
||||
}
|
||||
|
||||
|
||||
SGNODE* S3D::GetSGNodeParent( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return nullptr;
|
||||
|
||||
return aNode->GetParent();
|
||||
}
|
||||
|
||||
|
||||
bool S3D::AddSGNodeRef( SGNODE* aParent, SGNODE* aChild )
|
||||
{
|
||||
if( nullptr == aParent || nullptr == aChild )
|
||||
return false;
|
||||
|
||||
return aParent->AddRefNode( aChild );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::AddSGNodeChild( SGNODE* aParent, SGNODE* aChild )
|
||||
{
|
||||
if( nullptr == aParent || nullptr == aChild )
|
||||
return false;
|
||||
|
||||
return aParent->AddChildNode( aChild );
|
||||
}
|
||||
|
||||
|
||||
void S3D::AssociateSGNodeWrapper( SGNODE* aObject, SGNODE** aRefPtr )
|
||||
{
|
||||
if( nullptr == aObject || nullptr == aRefPtr || aObject != *aRefPtr )
|
||||
return;
|
||||
|
||||
aObject->AssociateWrapper( aRefPtr );
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
#include "plugins/3dapi/ifsg_appearance.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_APPEARANCE::IFSG_APPEARANCE( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGAPPEARANCE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGAPPEARANCE( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGAPPEARANCE" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetEmissive( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetDiffuse( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetSpecular( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGAPPEARANCE*) m_node )->SetAmbient( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetShininess( float aShininess ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aShininess < 0 || aShininess > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] shininess out of range [0..1]" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SGAPPEARANCE*) m_node )->shininess = aShininess;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_APPEARANCE::SetTransparency( float aTransparency ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aTransparency < 0 || aTransparency > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] transparency out of range [0..1]" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SGAPPEARANCE*) m_node )->transparency = aTransparency;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_colors.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d" ), __FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COLORS::IFSG_COLORS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Braces needed due to dangling else warning from wxLogTrace macro
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGCOLORS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COLORS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOLORS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOLORS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGCOLORS*) m_node )->GetColorList( aListSize, aColorList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->SetColorList( aListSize, aColorList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->AddColor( aRedValue, aGreenValue, aBlueValue );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COLORS::AddColor( const SGCOLOR& aColor )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOLORS*) m_node )->AddColor( aColor );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDINDEX::IFSG_COORDINDEX( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node = new SGCOORDINDEX( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOORDINDEX( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDINDEX" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDINDEX::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_coords.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_COORDS::IFSG_COORDS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGCOORDS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGCOORDS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGCOORDS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGCOORDS*) m_node )->GetCoordsList( aListSize, aCoordsList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->SetCoordsList( aListSize, aCoordsList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->AddCoord( aXValue, aYValue, aZValue );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_COORDS::AddCoord( const SGPOINT& aPoint )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGCOORDS*) m_node )->AddCoord( aPoint );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_faceset.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_FACESET::IFSG_FACESET( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGFACESET( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_FACESET != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGFACESET( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGFACESET" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
if( m_node )
|
||||
return ( (SGFACESET*) m_node )->CalcNormals( aPtr );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_index.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
IFSG_INDEX::IFSG_INDEX() : IFSG_NODE()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::GetIndices( size_t& nIndices, int*& aIndexList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGINDEX*) m_node )->GetIndices( nIndices, aIndexList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGINDEX*) m_node )->SetIndices( nIndices, aIndexList );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_INDEX::AddIndex( int aIndex )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGINDEX*) m_node )->AddIndex( aIndex );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_node.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "plugins/3dapi/ifsg_api.h"
|
||||
|
||||
|
||||
// collection of common error strings used by the wrappers
|
||||
char BadObject[] = " * [BUG] operating on an invalid wrapper (object may have been deleted)";
|
||||
char BadOperand[] = " * [BUG] parameter aNode is an invalid wrapper; its data may have been deleted";
|
||||
char BadParent[] = " * [BUG] invalid parent node (data may have been deleted)";
|
||||
char WrongParent[] = " * [BUG] parent node type is incompatible";
|
||||
|
||||
|
||||
IFSG_NODE::IFSG_NODE()
|
||||
{
|
||||
m_node = nullptr;
|
||||
}
|
||||
|
||||
|
||||
IFSG_NODE::~IFSG_NODE()
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
void IFSG_NODE::Destroy( void )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::GetRawPtr( void ) noexcept
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
|
||||
{
|
||||
wxCHECK( m_node, S3D::SGTYPE_END );
|
||||
|
||||
return m_node->GetNodeType();
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::GetParent( void ) const
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetParent();
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::SetParent( SGNODE* aParent )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->SetParent( aParent );
|
||||
}
|
||||
|
||||
|
||||
const char* IFSG_NODE::GetName( void )
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetName();
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::SetName( const char* aName )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
m_node->SetName( aName );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char* IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->GetNodeTypeName( aNodeType );
|
||||
}
|
||||
|
||||
|
||||
SGNODE* IFSG_NODE::FindNode( const char* aNodeName )
|
||||
{
|
||||
wxCHECK( m_node, nullptr );
|
||||
|
||||
return m_node->FindNode( aNodeName, nullptr );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->AddRefNode( aNode );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
SGNODE* np = aNode.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return m_node->AddRefNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return m_node->AddChildNode( aNode );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NODE::AddChildNode( IFSG_NODE& aNode )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
SGNODE* np = aNode.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return m_node->AddChildNode( np );
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_normals.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_NORMALS::IFSG_NORMALS( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( ! pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGNORMALS( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_NORMALS != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGNORMALS( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGNORMALS" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
return ( (SGNORMALS*) m_node )->GetNormalList( aListSize, aNormalList );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->SetNormalList( aListSize, aNormalList );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->AddNormal( aXValue, aYValue, aZValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_NORMALS::AddNormal( const SGVECTOR& aNormal )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SGNORMALS*) m_node )->AddNormal( aNormal );
|
||||
return true;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_shape.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
|
||||
|
||||
extern char BadParent[];
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return ;
|
||||
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_SHAPE::IFSG_SHAPE( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* pp = aParent.GetRawPtr();
|
||||
|
||||
#ifdef DEBUG
|
||||
if( !pp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
BadParent );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_node = new SGSHAPE( nullptr );
|
||||
|
||||
if( !m_node->SetParent( pp ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_SHAPE != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SGSHAPE( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SGSHAPE" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_SHAPE::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/ifsg_transform.h"
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
|
||||
|
||||
extern char WrongParent[];
|
||||
|
||||
|
||||
IFSG_TRANSFORM::IFSG_TRANSFORM( bool create )
|
||||
{
|
||||
m_node = nullptr;
|
||||
|
||||
if( !create )
|
||||
return;
|
||||
|
||||
m_node = new SCENEGRAPH( nullptr );
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
IFSG_TRANSFORM::IFSG_TRANSFORM( SGNODE* aParent )
|
||||
{
|
||||
m_node = new SCENEGRAPH( nullptr );
|
||||
|
||||
if( !m_node->SetParent( aParent ) )
|
||||
{
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d %s" ), __FILE__, __FUNCTION__, __LINE__,
|
||||
WrongParent );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::Attach( SGNODE* aNode )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
if( !aNode )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_TRANSFORM != aNode->GetNodeType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node = aNode;
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::NewNode( SGNODE* aParent )
|
||||
{
|
||||
if( m_node )
|
||||
m_node->DisassociateWrapper( &m_node );
|
||||
|
||||
m_node = new SCENEGRAPH( aParent );
|
||||
|
||||
if( aParent != m_node->GetParent() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid SGNODE parent (%s) to SCENEGRAPH" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeTypeName( aParent->GetNodeType() ) );
|
||||
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_node->AssociateWrapper( &m_node );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
|
||||
{
|
||||
SGNODE* np = aParent.GetRawPtr();
|
||||
|
||||
wxCHECK( np, false );
|
||||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetRotation( const SGVECTOR& aRotationAxis, double aAngle )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->rotation_axis = aRotationAxis;
|
||||
( (SCENEGRAPH*) m_node )->rotation_angle = aAngle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale = aScale;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScale( double aScale )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
if( aScale < 1e-8 && aScale > -1e-8 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] |scale| is < 1e-8 - this seems strange" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale = SGPOINT( aScale, aScale, aScale );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->translation = aTranslation;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle )
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->scale_axis = aScaleAxis;
|
||||
( (SCENEGRAPH*) m_node )->scale_angle = aAngle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter ) noexcept
|
||||
{
|
||||
wxCHECK( m_node, false );
|
||||
|
||||
( (SCENEGRAPH*) m_node )->center = aCenter;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,733 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/scenegraph.h"
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_TRANSFORM;
|
||||
rotation_angle = 0.0;
|
||||
scale_angle = 0.0;
|
||||
|
||||
scale.x = 1.0;
|
||||
scale.y = 1.0;
|
||||
scale.z = 1.0;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SCENEGRAPH (type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SCENEGRAPH::~SCENEGRAPH()
|
||||
{
|
||||
// drop references
|
||||
DROP_REFS( SCENEGRAPH, m_RTransforms );
|
||||
DROP_REFS( SGSHAPE, m_RShape );
|
||||
|
||||
// delete owned objects
|
||||
DEL_OBJS( SCENEGRAPH, m_Transforms );
|
||||
DEL_OBJS( SGSHAPE, m_Shape );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a transform may be parent to a transform
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
FIND_NODE( SCENEGRAPH, aNodeName, m_Transforms, aCaller );
|
||||
FIND_NODE( SGSHAPE, aNodeName, m_Shape, aCaller );
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
switch( aNode->GetNodeType() )
|
||||
{
|
||||
case S3D::SGTYPE_TRANSFORM:
|
||||
UNLINK_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms,
|
||||
isChild );
|
||||
break;
|
||||
|
||||
case S3D::SGTYPE_SHAPE:
|
||||
UNLINK_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
ADD_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms, isChild );
|
||||
ADD_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] object '%s' is not a valid type for this object (%d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aNode->GetName(),
|
||||
aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SCENEGRAPH::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename all shapes
|
||||
do
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->ReNameNodes();
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// rename all transforms
|
||||
do
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->ReNameNodes();
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "DEF " << GetName() << " Transform {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " Transform {\n";
|
||||
}
|
||||
|
||||
// convert center to 1VRML unit = 0.1 inch
|
||||
SGPOINT pt = center;
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << " center " << tmp << "\n";
|
||||
S3D::FormatOrientation( tmp, rotation_axis, rotation_angle );
|
||||
aFile << " rotation " << tmp << "\n";
|
||||
S3D::FormatPoint( tmp, scale );
|
||||
aFile << " scale " << tmp << "\n";
|
||||
S3D::FormatOrientation( tmp, scale_axis, scale_angle );
|
||||
aFile << " scaleOrientation " << tmp << "\n";
|
||||
|
||||
// convert translation to 1VRML unit = 0.1 inch
|
||||
pt = translation;
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << " translation " << tmp << "\n";
|
||||
|
||||
aFile << " children [\n";
|
||||
|
||||
if( !m_Transforms.empty() )
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_RTransforms.empty() )
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_RTransforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_RTransforms.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_Shape.empty() )
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_RShape.empty() )
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_RShape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_RShape.end();
|
||||
|
||||
while( sL != eL )
|
||||
{
|
||||
(*sL)->WriteVRML( aFile, aReuseFlag );
|
||||
++sL;
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode && nullptr != m_Parent )
|
||||
{
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( nullptr == m_Parent )
|
||||
{
|
||||
// ensure unique node names
|
||||
ResetNodeIndex();
|
||||
ReNameNodes();
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
S3D::WritePoint( aFile, center );
|
||||
S3D::WritePoint( aFile, translation );
|
||||
S3D::WriteVector( aFile, rotation_axis );
|
||||
aFile.write( (char*)&rotation_angle, sizeof( rotation_angle ) );
|
||||
S3D::WritePoint( aFile, scale );
|
||||
S3D::WriteVector( aFile, scale_axis );
|
||||
aFile.write( (char*)&scale_angle, sizeof( scale_angle ) );
|
||||
|
||||
// Transfer ownership of any Transform references which hadn't been written
|
||||
size_t asize = m_RTransforms.size();
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_RTransforms[i]->isWritten() )
|
||||
{
|
||||
m_RTransforms[i]->SwapParent( this );
|
||||
--asize;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer ownership of any Shape references which hadn't been written
|
||||
asize = m_RShape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_RShape[i]->isWritten() )
|
||||
{
|
||||
m_RShape[i]->SwapParent( this );
|
||||
--asize;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
asize = m_Transforms.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_RTransforms.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_Shape.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_RShape.size();
|
||||
aFile.write( (char*)&asize, sizeof( size_t ) );
|
||||
asize = m_Transforms.size();
|
||||
|
||||
// write child transforms
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_Transforms[i]->WriteCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] bad stream while writing child transforms" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// write referenced transform names
|
||||
asize = m_RTransforms.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
aFile << "[" << m_RTransforms[i]->GetName() << "]";
|
||||
|
||||
// write child shapes
|
||||
asize = m_Shape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
{
|
||||
if( !m_Shape[i]->WriteCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [INFO] bad stream while writing child shapes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// write referenced transform names
|
||||
asize = m_RShape.size();
|
||||
|
||||
for( i = 0; i < asize; ++i )
|
||||
aFile << "[" << m_RShape[i]->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( m_Transforms.empty() && m_RTransforms.empty() && m_Shape.empty() && m_RShape.empty(),
|
||||
false );
|
||||
|
||||
std::string name; // name of the node
|
||||
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
// we need to read the tag and verify its type
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; tag mismatch at position "
|
||||
"%ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
// read fixed member data
|
||||
S3D::ReadPoint( aFile, center );
|
||||
S3D::ReadPoint( aFile, translation );
|
||||
S3D::ReadVector( aFile, rotation_axis );
|
||||
aFile.read( (char*)&rotation_angle, sizeof( rotation_angle ) );
|
||||
S3D::ReadPoint( aFile, scale );
|
||||
S3D::ReadVector( aFile, scale_axis );
|
||||
aFile.read( (char*)&scale_angle, sizeof( scale_angle ) );
|
||||
|
||||
size_t sizeCT = 0; // child transforms
|
||||
size_t sizeRT = 0; // referenced transforms
|
||||
size_t sizeCS = 0; // child shapes
|
||||
size_t sizeRS = 0; // referenced shapes
|
||||
|
||||
aFile.read( (char*)&sizeCT, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeRT, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeCS, sizeof( size_t ) );
|
||||
aFile.read( (char*)&sizeRS, sizeof( size_t ) );
|
||||
|
||||
size_t i;
|
||||
|
||||
// read child transforms
|
||||
for( i = 0; i < sizeCT; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child transform tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SCENEGRAPH* sp = new SCENEGRAPH( this );
|
||||
sp->SetName( name.c_str() );
|
||||
|
||||
if( !sp->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading transform "
|
||||
"%ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// read referenced transforms
|
||||
for( i = 0; i < sizeRT; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref transform tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* sp = FindNode( name.c_str(), this );
|
||||
|
||||
if( !sp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
|
||||
"transform at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_TRANSFORM != sp->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not TRANSFORM "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AddRefNode( sp );
|
||||
}
|
||||
|
||||
// read child shapes
|
||||
for( i = 0; i < sizeCS; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child shape tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGSHAPE* sp = new SGSHAPE( this );
|
||||
sp->SetName( name.c_str() );
|
||||
|
||||
if( !sp->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
|
||||
"reading shape at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// read referenced shapes
|
||||
for( i = 0; i < sizeRS; ++i )
|
||||
{
|
||||
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref shape tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* sp = FindNode( name.c_str(), this );
|
||||
|
||||
if( !sp )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref shape "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_SHAPE != sp->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGSHAPE at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AddRefNode( sp );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes )
|
||||
{
|
||||
// calculate the accumulated transform
|
||||
double rX, rY, rZ;
|
||||
|
||||
// rotation
|
||||
rotation_axis.GetVector( rX, rY, rZ );
|
||||
glm::dmat4 rM = glm::rotate( glm::dmat4( 1.0 ), rotation_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
|
||||
// translation
|
||||
glm::dmat4 tM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( translation.x, translation.y,
|
||||
translation.z ) );
|
||||
// center
|
||||
glm::dmat4 cM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( center.x, center.y, center.z ) );
|
||||
glm::dmat4 ncM = glm::translate( glm::dmat4( 1.0 ), glm::dvec3( -center.x, -center.y,
|
||||
-center.z ) );
|
||||
|
||||
// scale
|
||||
glm::dmat4 sM = glm::scale( glm::dmat4( 1.0 ), glm::dvec3( scale.x, scale.y, scale.z ) );
|
||||
|
||||
// scaleOrientation
|
||||
scale_axis.GetVector( rX, rY, rZ );
|
||||
glm::dmat4 srM = glm::rotate( glm::dmat4( 1.0 ), scale_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
glm::dmat4 nsrM = glm::rotate( glm::dmat4( 1.0 ), -scale_angle, glm::dvec3( rX, rY, rZ ) );
|
||||
|
||||
// resultant point:
|
||||
// P' = T x C x R x SR x S x -SR x -C x P
|
||||
// resultant transform:
|
||||
// tx0 = tM * cM * rM * srM * sM * nsrM * ncM
|
||||
glm::dmat4 tx0;
|
||||
|
||||
if( nullptr != aTransform )
|
||||
tx0 = (*aTransform) * tM * cM * rM * srM * sM * nsrM * ncM;
|
||||
else
|
||||
tx0 = tM * cM * rM * srM * sM * nsrM * ncM;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
// prepare all shapes
|
||||
do
|
||||
{
|
||||
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
|
||||
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
sL = m_RShape.begin();
|
||||
eL = m_RShape.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
// prepare all transforms
|
||||
do
|
||||
{
|
||||
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
|
||||
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
sL = m_RTransforms.begin();
|
||||
eL = m_RTransforms.end();
|
||||
|
||||
while( sL != eL && ok )
|
||||
{
|
||||
ok = (*sL)->Prepare( &tx0, materials, meshes );
|
||||
++sL;
|
||||
}
|
||||
|
||||
} while( 0 );
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file scenegraph.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SCENE_GRAPH_H
|
||||
#define SCENE_GRAPH_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGSHAPE;
|
||||
|
||||
/**
|
||||
* Define the basic data set required to represent a 3D model.
|
||||
*
|
||||
* This model must remain compatible with VRML2.0 in order to facilitate VRML export of
|
||||
* scene graph data created by available 3D plugins.
|
||||
*/
|
||||
class SCENEGRAPH : public SGNODE
|
||||
{
|
||||
public:
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
SCENEGRAPH( SGNODE* aParent );
|
||||
virtual ~SCENEGRAPH();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes );
|
||||
|
||||
private:
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
public:
|
||||
// note: order of transformation is Translate, Rotate, Offset
|
||||
SGPOINT center;
|
||||
SGPOINT translation;
|
||||
SGVECTOR rotation_axis;
|
||||
double rotation_angle; // radians
|
||||
SGPOINT scale;
|
||||
SGVECTOR scale_axis;
|
||||
double scale_angle; // radians
|
||||
|
||||
private:
|
||||
// The following are items which may be defined for reuse
|
||||
// in a VRML output file. They do not necessarily correspond
|
||||
// to the use of DEF within a VRML input file; it is the
|
||||
// responsibility of the plugin to perform any necessary
|
||||
// conversions to comply with the restrictions imposed by
|
||||
// this scene graph structure
|
||||
std::vector< SCENEGRAPH* > m_Transforms; // local Transform nodes
|
||||
std::vector< SGSHAPE* > m_Shape; // local Shape nodes
|
||||
|
||||
std::vector< SCENEGRAPH* > m_RTransforms; // referenced Transform nodes
|
||||
std::vector< SGSHAPE* > m_RShape; // referenced Shape nodes
|
||||
};
|
||||
|
||||
/*
|
||||
p.120
|
||||
Transform {
|
||||
center 0 0 0
|
||||
children []
|
||||
rotation 0 0 1 0
|
||||
scale 1 1 1
|
||||
scaleOrientation 0 0 1 0
|
||||
translation 0 0 0
|
||||
bboxCenter 0 0 0
|
||||
bboxSize -1 -1 -1
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SCENE_GRAPH_H
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGAPPEARANCE::SGAPPEARANCE( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_APPEARANCE;
|
||||
|
||||
// defaults in accord with VRML2.0 spec
|
||||
ambient.SetColor( 0.05317f, 0.17879f, 0.01804f );
|
||||
shininess = 0.2f;
|
||||
transparency = 0.0f;
|
||||
diffuse.SetColor( 0.8f, 0.8f, 0.8f );
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGAPPEARANCE (type %s )" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGAPPEARANCE::~SGAPPEARANCE()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGSHAPE may be parent to a SGAPPEARANCE
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return emissive.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return emissive.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return emissive.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return diffuse.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return diffuse.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return diffuse.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return specular.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return specular.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
bool SGAPPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return specular.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
return ambient.SetColor( aRVal, aGVal, aBVal );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( const SGCOLOR* aRGBColor )
|
||||
{
|
||||
wxCHECK_MSG( aRGBColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
return ambient.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::SetAmbient( const SGCOLOR& aRGBColor )
|
||||
{
|
||||
return ambient.SetColor( aRGBColor );
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGAPPEARANCE::FindNode( const char* aNodeName, const SGNODE* aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aCaller, /* void */,
|
||||
wxT( "unexpected code branch; node should have no children or refs" ) );
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aCaller, /* void */,
|
||||
wxT( "unexpected code branch; node should have no children or refs" ) );
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
|
||||
|
||||
// This is redundant but it keeps gcc from generating a warning on debug builds.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aNode, false, wxT( "this node does not accept children or refs" ) );
|
||||
|
||||
// This is redundant but it keeps gcc from generating a warning on debug builds.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SGAPPEARANCE::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " appearance DEF " << GetName() << " Appearance {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " appearance USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " appearance Appearance {\n";
|
||||
}
|
||||
|
||||
aFile << " material Material {\n";
|
||||
|
||||
std::string tmp;
|
||||
float ambr, ambg, ambb;
|
||||
ambient.GetColor( ambr, ambg, ambb );
|
||||
float amb = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
|
||||
diffuse.GetColor( ambr, ambg, ambb );
|
||||
float den = ( 0.212671 * ambr + 0.71516 * ambg + 0.072169 * ambb );
|
||||
|
||||
if( den < 0.004f )
|
||||
den = 0.004f;
|
||||
|
||||
amb /= den;
|
||||
|
||||
if( amb > 1.0f )
|
||||
amb = 1.0f;
|
||||
|
||||
S3D::FormatFloat( tmp, amb );
|
||||
aFile << " ambientIntensity " << tmp << "\n";
|
||||
|
||||
float red, green, blue;
|
||||
diffuse.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " diffuseColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
emissive.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " emissiveColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
S3D::FormatFloat( tmp, shininess );
|
||||
aFile << " shininess " << tmp << "\n";
|
||||
|
||||
specular.GetColor( red, green, blue );
|
||||
S3D::FormatFloat( tmp, red );
|
||||
aFile << " specularColor " << tmp << " ";
|
||||
S3D::FormatFloat( tmp, green );
|
||||
aFile << tmp << " ";
|
||||
S3D::FormatFloat( tmp, blue);
|
||||
aFile << tmp << "\n";
|
||||
|
||||
S3D::FormatFloat( tmp, transparency );
|
||||
aFile << " transparency " << tmp << "\n";
|
||||
|
||||
aFile << "} }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK_MSG( m_Parent, false, wxT( "corrupt data; m_aParent is NULL" ) );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( parentNode == m_Parent, false, wxT( "corrupt data; parentNode != m_aParent" ) );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
S3D::WriteColor( aFile, ambient );
|
||||
aFile.write( (char*) &shininess, sizeof( shininess ) );
|
||||
aFile.write( (char*) &transparency, sizeof( transparency ) );
|
||||
S3D::WriteColor( aFile, diffuse );
|
||||
S3D::WriteColor( aFile, emissive );
|
||||
S3D::WriteColor( aFile, specular );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGAPPEARANCE::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
S3D::ReadColor( aFile, ambient );
|
||||
aFile.read( (char*) &shininess, sizeof( shininess ) );
|
||||
aFile.read( (char*) &transparency, sizeof( transparency ) );
|
||||
S3D::ReadColor( aFile, diffuse );
|
||||
S3D::ReadColor( aFile, emissive );
|
||||
S3D::ReadColor( aFile, specular );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_appearance.h
|
||||
*/
|
||||
|
||||
#ifndef SG_APPEARANCE_H
|
||||
#define SG_APPEARANCE_H
|
||||
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Defines the generic material appearance of a scenegraph object.
|
||||
*/
|
||||
class SGAPPEARANCE : public SGNODE
|
||||
{
|
||||
public:
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
SGAPPEARANCE( SGNODE* aParent );
|
||||
virtual ~SGAPPEARANCE();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
bool SetEmissive( float aRVal, float aGVal, float aBVal );
|
||||
bool SetEmissive( const SGCOLOR* aRGBColor );
|
||||
bool SetEmissive( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
|
||||
bool SetDiffuse( const SGCOLOR* aRGBColor );
|
||||
bool SetDiffuse( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetSpecular( float aRVal, float aGVal, float aBVal );
|
||||
bool SetSpecular( const SGCOLOR* aRGBColor );
|
||||
bool SetSpecular( const SGCOLOR& aRGBColor );
|
||||
|
||||
bool SetAmbient( float aRVal, float aGVal, float aBVal );
|
||||
bool SetAmbient( const SGCOLOR* aRGBColor );
|
||||
bool SetAmbient( const SGCOLOR& aRGBColor );
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
float shininess; // default 0.2
|
||||
float transparency; // default 0.0
|
||||
SGCOLOR ambient; // default 0.05317 0.17879 0.01804
|
||||
SGCOLOR diffuse; // default 0.8 0.8 0.8
|
||||
SGCOLOR emissive; // default 0.0 0.0 0.0
|
||||
SGCOLOR specular; // default 0.0 0.0 0.0
|
||||
|
||||
};
|
||||
|
||||
#endif // SG_APPEARANCE_H
|
||||
@@ -1,276 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
|
||||
|
||||
SGCOLOR::SGCOLOR()
|
||||
{
|
||||
red = 0.0;
|
||||
green = 0.0;
|
||||
blue = 0.0;
|
||||
}
|
||||
|
||||
SGCOLOR::SGCOLOR( float aRVal, float aGVal, float aBVal )
|
||||
{
|
||||
if( !checkRange( aRVal, aGVal, aBVal ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid value passed to constructor" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
red = 0.0;
|
||||
green = 0.0;
|
||||
blue = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
red = aRVal;
|
||||
green = aGVal;
|
||||
blue = aBVal;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const noexcept
|
||||
{
|
||||
aRedVal = red;
|
||||
aGreenVal = green;
|
||||
aBlueVal = blue;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( SGCOLOR& aColor ) const noexcept
|
||||
{
|
||||
aColor.red = red;
|
||||
aColor.green = green;
|
||||
aColor.blue = blue;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLOR::GetColor( SGCOLOR* aColor ) const noexcept
|
||||
{
|
||||
wxCHECK_MSG( aColor, /* void */, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
aColor->red = red;
|
||||
aColor->green = green;
|
||||
aColor->blue = blue;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( float aRedVal, float aGreenVal, float aBlueVal )
|
||||
{
|
||||
if( !checkRange( aRedVal, aGreenVal, aBlueVal ) )
|
||||
return false;
|
||||
|
||||
red = aRedVal;
|
||||
green = aGreenVal;
|
||||
blue = aBlueVal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( const SGCOLOR& aColor ) noexcept
|
||||
{
|
||||
red = aColor.red;
|
||||
green = aColor.green;
|
||||
blue = aColor.blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::SetColor( const SGCOLOR* aColor ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aColor, false, wxT( "NULL pointer passed for aRGBColor" ) );
|
||||
|
||||
red = aColor->red;
|
||||
green = aColor->green;
|
||||
blue = aColor->blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const noexcept
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if( aRedVal < 0.0 || aRedVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid RED value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aRedVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if( aGreenVal < 0.0 || aGreenVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid GREEN value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aGreenVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if( aBlueVal < 0.0 || aBlueVal > 1.0 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] invalid BLUE value: %g" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aBlueVal );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
SGPOINT::SGPOINT()
|
||||
{
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
z = 0.0;
|
||||
}
|
||||
|
||||
|
||||
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const double& aXVal, const double& aYVal, const double& aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const SGPOINT& aPoint ) noexcept
|
||||
{
|
||||
x = aPoint.x;
|
||||
y = aPoint.y;
|
||||
z = aPoint.z;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::GetPoint( const SGPOINT* aPoint ) noexcept
|
||||
{
|
||||
wxCHECK_MSG( aPoint, /* void */, wxT( "NULL pointer passed for aPoint" ) );
|
||||
|
||||
x = aPoint->x;
|
||||
y = aPoint->y;
|
||||
z = aPoint->z;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal ) noexcept
|
||||
{
|
||||
x = aXVal;
|
||||
y = aYVal;
|
||||
z = aZVal;
|
||||
}
|
||||
|
||||
|
||||
void SGPOINT::SetPoint( const SGPOINT& aPoint ) noexcept
|
||||
{
|
||||
x = aPoint.x;
|
||||
y = aPoint.y;
|
||||
z = aPoint.z;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR::SGVECTOR()
|
||||
{
|
||||
vx = 0.0;
|
||||
vy = 0.0;
|
||||
vz = 1.0;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR::SGVECTOR( double aXVal, double aYVal, double aZVal )
|
||||
{
|
||||
vx = aXVal;
|
||||
vy = aYVal;
|
||||
vz = aZVal;
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const noexcept
|
||||
{
|
||||
aXVal = vx;
|
||||
aYVal = vy;
|
||||
aZVal = vz;
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::SetVector( double aXVal, double aYVal, double aZVal )
|
||||
{
|
||||
vx = aXVal;
|
||||
vy = aYVal;
|
||||
vz = aZVal;
|
||||
normalize();
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::SetVector( const SGVECTOR& aVector )
|
||||
{
|
||||
aVector.GetVector( vx, vy, vz );
|
||||
}
|
||||
|
||||
|
||||
void SGVECTOR::normalize( void ) noexcept
|
||||
{
|
||||
double dx = vx * vx;
|
||||
double dy = vy * vy;
|
||||
double dz = vz * vz;
|
||||
double dv2 = sqrt( dx + dy + dz );
|
||||
|
||||
if( ( dx + dy + dz ) < 1e-8 )
|
||||
{
|
||||
// use the default; the numbers are too small to be believable
|
||||
vx = 0.0;
|
||||
vy = 0.0;
|
||||
vz = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
vx /= dv2;
|
||||
vy /= dv2;
|
||||
vz /= dv2;
|
||||
}
|
||||
|
||||
|
||||
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source ) noexcept
|
||||
{
|
||||
vx = source.vx;
|
||||
vy = source.vy;
|
||||
vz = source.vz;
|
||||
return *this;
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGCOLORS::SGCOLORS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COLORS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOLORS (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOLORS::~SGCOLORS()
|
||||
{
|
||||
colors.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGCOLORS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGCOLORS::FindNode(const char* aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
|
||||
{
|
||||
if( colors.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aColorList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = colors.size();
|
||||
aColorList = &colors[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::SetColorList( size_t aListSize, const SGCOLOR* aColorList )
|
||||
{
|
||||
colors.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aColorList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < aListSize; ++i )
|
||||
colors.push_back( aColorList[i] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
|
||||
{
|
||||
colors.emplace_back( aRedValue, aGreenValue, aBlueValue );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::AddColor( const SGCOLOR& aColor )
|
||||
{
|
||||
colors.push_back( aColor );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOLORS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( colors.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "color DEF " << GetName() << " Color { color [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "color USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "color Color { color [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = colors.size();
|
||||
bool nline = false;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
S3D::FormatColor( tmp, colors[i] );
|
||||
float r,g,b;
|
||||
colors[i].GetColor(r, g, b);
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t ncolors = colors.size();
|
||||
aFile.write( (char*)&ncolors, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < ncolors; ++i )
|
||||
S3D::WriteColor( aFile, colors[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOLORS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( colors.empty(), false );
|
||||
|
||||
size_t ncolors;
|
||||
aFile.read( (char*) &ncolors, sizeof( size_t ) );
|
||||
SGCOLOR tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < ncolors; ++i )
|
||||
{
|
||||
if( !S3D::ReadColor( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
colors.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_colors.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COLORS_H
|
||||
#define SG_COLORS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define an RGB color set for a scenegraph object.
|
||||
*/
|
||||
class SGCOLORS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGCOLORS( SGNODE* aParent );
|
||||
virtual ~SGCOLORS();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
|
||||
void SetColorList( size_t aListSize, const SGCOLOR* aColorList );
|
||||
void AddColor( double aRedValue, double aGreenValue, double aBlueValue );
|
||||
void AddColor( const SGCOLOR& aColor );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
std::vector< SGCOLOR > colors;
|
||||
};
|
||||
|
||||
#endif // SG_COLORS_H
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
|
||||
|
||||
SGCOORDINDEX::SGCOORDINDEX( SGNODE* aParent ) : SGINDEX( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COORDINDEX;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOORDINDEX::~SGCOORDINDEX()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDINDEX::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( index.empty() )
|
||||
return;
|
||||
|
||||
aIndexList.insert( aIndexList.end(), index.begin(), index.end() );
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_coordindex.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COORDINDEX_H
|
||||
#define SG_COORDINDEX_H
|
||||
|
||||
#include "3d_cache/sg/sg_index.h"
|
||||
|
||||
/**
|
||||
* An object to maintain a coordinate index list.
|
||||
*
|
||||
* Users must ensure that coordinate indices are specified as triplets (triangular faces)
|
||||
* since no checking is performed. In instances where it is not possible to determine which
|
||||
* side of the triangle is to be rendered (for example IGES entities) then the user must
|
||||
* supply each triplet in both point orders.
|
||||
*/
|
||||
class SGCOORDINDEX : public SGINDEX
|
||||
{
|
||||
public:
|
||||
SGCOORDINDEX( SGNODE* aParent );
|
||||
virtual ~SGCOORDINDEX();
|
||||
|
||||
/**
|
||||
* Add all coordinate indices to the given list in preparation for a normals calculation.
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
};
|
||||
|
||||
#endif // SG_COORDINDEX_H
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
|
||||
|
||||
SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_COORDS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGCOORDS (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGCOORDS::~SGCOORDS()
|
||||
{
|
||||
coords.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGCOORDS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( aCaller, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
|
||||
{
|
||||
if( coords.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aCoordsList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = coords.size();
|
||||
aCoordsList = &coords[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
|
||||
{
|
||||
coords.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aCoordsList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < aListSize; ++i )
|
||||
coords.push_back( aCoordsList[i] );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
coords.emplace_back( aXValue, aYValue, aZValue );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::AddCoord( const SGPOINT& aPoint )
|
||||
{
|
||||
coords.push_back( aPoint );
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( coords.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " coord DEF " << GetName() << " Coordinate { point [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " coord USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " coord Coordinate { point [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = coords.size();
|
||||
bool nline = false;
|
||||
SGPOINT pt;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
// ensure VRML output has 1U = 0.1 inch as per legacy kicad expectations
|
||||
pt = coords[i];
|
||||
pt.x /= 2.54;
|
||||
pt.y /= 2.54;
|
||||
pt.z /= 2.54;
|
||||
S3D::FormatPoint( tmp, pt );
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = coords.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
S3D::WritePoint( aFile, coords[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( coords.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*) &npts, sizeof( size_t ) );
|
||||
SGPOINT tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
if( !S3D::ReadPoint( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
coords.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::CalcNormals( SGFACESET* callingNode, SGNODE** aPtr )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = nullptr;
|
||||
|
||||
if( nullptr == m_Parent || nullptr == callingNode )
|
||||
return false;
|
||||
|
||||
// the parent and all references must have indices; collect all
|
||||
// indices into one std::vector<>
|
||||
std::vector< int > ilist;
|
||||
SGNORMALS* np = nullptr;
|
||||
|
||||
if( callingNode == m_Parent )
|
||||
{
|
||||
((SGFACESET*)m_Parent)->GatherCoordIndices( ilist );
|
||||
|
||||
std::list< SGNODE* >::iterator sB = m_BackPointers.begin();
|
||||
std::list< SGNODE* >::iterator eB = m_BackPointers.end();
|
||||
|
||||
while( sB != eB )
|
||||
{
|
||||
SGFACESET* fp = (SGFACESET*)(*sB);
|
||||
fp->GatherCoordIndices( ilist );
|
||||
++sB;
|
||||
}
|
||||
|
||||
np = ( (SGFACESET*) m_Parent )->m_Normals;
|
||||
|
||||
if( !np )
|
||||
np = new SGNORMALS( m_Parent );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
callingNode->GatherCoordIndices( ilist );
|
||||
np = callingNode->m_Normals;
|
||||
|
||||
if( !np )
|
||||
np = new SGNORMALS( callingNode );
|
||||
|
||||
}
|
||||
|
||||
if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = np;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
delete np;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_coords.h
|
||||
*/
|
||||
|
||||
#ifndef SG_COORDS_H
|
||||
#define SG_COORDS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGFACESET;
|
||||
|
||||
/**
|
||||
* Define a vertex coordinate set for a scenegraph object.
|
||||
*/
|
||||
class SGCOORDS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGCOORDS( SGNODE* aParent );
|
||||
virtual ~SGCOORDS();
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
|
||||
void SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
|
||||
void AddCoord( double aXValue, double aYValue, double aZValue );
|
||||
void AddCoord( const SGPOINT& aPoint );
|
||||
|
||||
/**
|
||||
* Calculate normals for this coordinate list and sets the normals list in the
|
||||
* parent #SGFACESET.
|
||||
*/
|
||||
bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = nullptr );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
std::vector< SGPOINT > coords;
|
||||
};
|
||||
|
||||
#endif // SG_COORDS_H
|
||||
@@ -1,992 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_FACESET;
|
||||
m_Colors = nullptr;
|
||||
m_Coords = nullptr;
|
||||
m_CoordIndices = nullptr;
|
||||
m_Normals = nullptr;
|
||||
m_RColors = nullptr;
|
||||
m_RCoords = nullptr;
|
||||
m_RNormals = nullptr;
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGFACESET::~SGFACESET()
|
||||
{
|
||||
// drop references
|
||||
if( m_RColors )
|
||||
{
|
||||
m_RColors->delNodeRef( this );
|
||||
m_RColors = nullptr;
|
||||
}
|
||||
|
||||
if( m_RCoords )
|
||||
{
|
||||
m_RCoords->delNodeRef( this );
|
||||
m_RCoords = nullptr;
|
||||
}
|
||||
|
||||
if( m_RNormals )
|
||||
{
|
||||
m_RNormals->delNodeRef( this );
|
||||
m_RNormals = nullptr;
|
||||
}
|
||||
|
||||
// delete owned objects
|
||||
if( m_Colors )
|
||||
{
|
||||
m_Colors->SetParent( nullptr, false );
|
||||
delete m_Colors;
|
||||
m_Colors = nullptr;
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
{
|
||||
m_Coords->SetParent( nullptr, false );
|
||||
delete m_Coords;
|
||||
m_Coords = nullptr;
|
||||
}
|
||||
|
||||
if( m_Normals )
|
||||
{
|
||||
m_Normals->SetParent( nullptr, false );
|
||||
delete m_Normals;
|
||||
m_Normals = nullptr;
|
||||
}
|
||||
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
m_CoordIndices->SetParent( nullptr, false );
|
||||
delete m_CoordIndices;
|
||||
m_CoordIndices = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGSHAPE may be parent to a SGFACESET
|
||||
if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
SGNODE* np = nullptr;
|
||||
|
||||
if( m_Colors )
|
||||
{
|
||||
np = m_Colors->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
{
|
||||
np = m_Coords->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
np = m_CoordIndices->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
if( m_Normals )
|
||||
{
|
||||
np = m_Normals->FindNode( aNodeName, this );
|
||||
|
||||
if( np )
|
||||
return np;
|
||||
}
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
if( aNode == m_Colors )
|
||||
{
|
||||
m_Colors = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_Coords )
|
||||
{
|
||||
m_Coords = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_Normals )
|
||||
{
|
||||
m_Normals = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_CoordIndices )
|
||||
{
|
||||
m_CoordIndices = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aNode == m_RColors )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RColors = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RCoords )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RCoords = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RNormals )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RNormals = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
valid = false;
|
||||
validated = false;
|
||||
|
||||
if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Colors || m_RColors )
|
||||
{
|
||||
if( aNode != m_Colors && aNode != m_RColors )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Colors = (SGCOLORS*)aNode;
|
||||
m_Colors->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RColors = (SGCOLORS*)aNode;
|
||||
m_RColors->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Coords || m_RCoords )
|
||||
{
|
||||
if( aNode != m_Coords && aNode != m_RCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Coords = (SGCOORDS*)aNode;
|
||||
m_Coords->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RCoords = (SGCOORDS*)aNode;
|
||||
m_RCoords->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Normals || m_RNormals )
|
||||
{
|
||||
if( aNode != m_Normals && aNode != m_RNormals )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Normals = (SGNORMALS*)aNode;
|
||||
m_Normals->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RNormals = (SGNORMALS*)aNode;
|
||||
m_RNormals->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_CoordIndices )
|
||||
{
|
||||
if( aNode != m_CoordIndices )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG,
|
||||
wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
m_CoordIndices = (SGCOORDINDEX*)aNode;
|
||||
m_CoordIndices->SetParent( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object type '%s' is not a valid type for "
|
||||
"this object '%d'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aNode->GetName(),
|
||||
aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename all Colors and Indices
|
||||
if( m_Colors )
|
||||
m_Colors->ReNameNodes();
|
||||
|
||||
// rename all Coordinates and Indices
|
||||
if( m_Coords )
|
||||
m_Coords->ReNameNodes();
|
||||
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->ReNameNodes();
|
||||
|
||||
// rename all Normals and Indices
|
||||
if( m_Normals )
|
||||
m_Normals->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << "USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " geometry IndexedFaceSet {\n";
|
||||
}
|
||||
|
||||
if( m_Coords )
|
||||
m_Coords->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RCoords )
|
||||
m_RCoords->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_Normals || m_RNormals )
|
||||
aFile << " normalPerVertex TRUE\n";
|
||||
|
||||
if( m_Normals )
|
||||
m_Normals->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RNormals )
|
||||
m_RNormals->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_Colors )
|
||||
m_Colors->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RColors )
|
||||
m_RColors->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
aFile << "}\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if any references are unwritten and swap parents if so
|
||||
if( nullptr != m_RCoords && !m_RCoords->isWritten() )
|
||||
m_RCoords->SwapParent( this );
|
||||
|
||||
if( nullptr != m_RNormals && !m_RNormals->isWritten() )
|
||||
m_RNormals->SwapParent( this );
|
||||
|
||||
if( nullptr != m_RColors && !m_RColors->isWritten() )
|
||||
m_RColors->SwapParent( this );
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
#define NITEMS 7
|
||||
bool items[NITEMS];
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NITEMS; ++i )
|
||||
items[i] = 0;
|
||||
|
||||
i = 0;
|
||||
if( nullptr != m_Coords )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RCoords )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_CoordIndices )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_Normals )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RNormals )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_Colors )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
if( nullptr != m_RColors )
|
||||
items[i] = true;
|
||||
|
||||
for( int jj = 0; jj < NITEMS; ++jj )
|
||||
aFile.write( (char*) &items[jj], sizeof( bool ) );
|
||||
|
||||
if( items[0] )
|
||||
m_Coords->WriteCache( aFile, this );
|
||||
|
||||
if( items[1] )
|
||||
aFile << "[" << m_RCoords->GetName() << "]";
|
||||
|
||||
if( items[2] )
|
||||
m_CoordIndices->WriteCache( aFile, this );
|
||||
|
||||
if( items[3] )
|
||||
m_Normals->WriteCache( aFile, this );
|
||||
|
||||
if( items[4] )
|
||||
aFile << "[" << m_RNormals->GetName() << "]";
|
||||
|
||||
if( items[5] )
|
||||
m_Colors->WriteCache( aFile, this );
|
||||
|
||||
if( items[6] )
|
||||
aFile << "[" << m_RColors->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( m_Coords || m_RCoords || m_CoordIndices || m_Colors || m_RColors || m_Normals
|
||||
|| m_RNormals )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] non-empty node" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define NITEMS 7
|
||||
bool items[NITEMS];
|
||||
|
||||
for( int i = 0; i < NITEMS; ++i )
|
||||
aFile.read( (char*) &items[i], sizeof( bool ) );
|
||||
|
||||
if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if( items[0] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child coords tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Coords = new SGCOORDS( this );
|
||||
m_Coords->SetName( name.c_str() );
|
||||
|
||||
if( !m_Coords->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
|
||||
"reading coords '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[1] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref coords tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
|
||||
"coords '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COORDS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; type is not SGCOORDS "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RCoords = (SGCOORDS*)np;
|
||||
m_RCoords->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[2] )
|
||||
{
|
||||
if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad coord index tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_CoordIndices = new SGCOORDINDEX( this );
|
||||
m_CoordIndices->SetName( name.c_str() );
|
||||
|
||||
if( !m_CoordIndices->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading coord "
|
||||
"index '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[3] )
|
||||
{
|
||||
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child normals tag "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Normals = new SGNORMALS( this );
|
||||
m_Normals->SetName( name.c_str() );
|
||||
|
||||
if( !m_Normals->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading normals "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[4] )
|
||||
{
|
||||
if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref normals tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: type is not SGNORMALS '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RNormals = (SGNORMALS*)np;
|
||||
m_RNormals->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[5] )
|
||||
{
|
||||
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child colors tag "
|
||||
"at position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Colors = new SGCOLORS( this );
|
||||
m_Colors->SetName( name.c_str() );
|
||||
|
||||
if( !m_Colors->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading colors "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[6] )
|
||||
{
|
||||
if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref colors tag at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_COLORS != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGCOLORS "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RColors = (SGCOLORS*)np;
|
||||
m_RColors->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::validate( void )
|
||||
{
|
||||
// verify the integrity of this object's data
|
||||
if( validated )
|
||||
return valid;
|
||||
|
||||
// ensure we have at least coordinates and their normals
|
||||
if( ( nullptr == m_Coords && nullptr == m_RCoords )
|
||||
|| ( nullptr == m_Normals && nullptr == m_RNormals )
|
||||
|| ( nullptr == m_CoordIndices ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
|
||||
"or normals" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that there are >3 vertices
|
||||
SGCOORDS* coords = m_Coords;
|
||||
|
||||
if( nullptr == coords )
|
||||
coords = m_RCoords;
|
||||
|
||||
size_t nCoords = 0;
|
||||
SGPOINT* lCoords = nullptr;
|
||||
coords->GetCoordsList( nCoords, lCoords );
|
||||
|
||||
if( nCoords < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; fewer than 3 vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that nVertices is divisible by 3 (facets are triangles)
|
||||
size_t nCIdx = 0;
|
||||
int* lCIdx = nullptr;
|
||||
m_CoordIndices->GetIndices( nCIdx, lCIdx );
|
||||
|
||||
if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertex indices or not "
|
||||
"multiple of 3" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that vertex[n] >= 0 and < nVertices
|
||||
for( size_t i = 0; i < nCIdx; ++i )
|
||||
{
|
||||
if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; vertex index out of "
|
||||
"bounds" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check that there are as many normals as vertices
|
||||
size_t nNorms = 0;
|
||||
SGVECTOR* lNorms = nullptr;
|
||||
SGNORMALS* pNorms = m_Normals;
|
||||
|
||||
if( nullptr == pNorms )
|
||||
pNorms = m_RNormals;
|
||||
|
||||
pNorms->GetNormalList( nNorms, lNorms );
|
||||
|
||||
if( nNorms != nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; number of normals (%ul) does "
|
||||
"not match number of vertices (%ul)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( nNorms ),
|
||||
static_cast<unsigned long>( nCoords ) );
|
||||
|
||||
validated = true;
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there are colors then ensure there are as many colors as vertices
|
||||
SGCOLORS* pColors = m_Colors;
|
||||
|
||||
if( nullptr == pColors )
|
||||
pColors = m_RColors;
|
||||
|
||||
if( nullptr != pColors )
|
||||
{
|
||||
// we must have at least as many colors as vertices
|
||||
size_t nColor = 0;
|
||||
SGCOLOR* pColor = nullptr;
|
||||
pColors->GetColorList( nColor, pColor );
|
||||
}
|
||||
|
||||
validated = true;
|
||||
valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->GatherCoordIndices( aIndexList );
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
SGCOORDS* coords = m_Coords;
|
||||
|
||||
if( m_RCoords )
|
||||
coords = m_RCoords;
|
||||
|
||||
if( nullptr == coords || coords->coords.empty() )
|
||||
return false;
|
||||
|
||||
if( m_Normals && !m_Normals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
if( m_RNormals && !m_RNormals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
return coords->CalcNormals( this, aPtr );
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_faceset.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_FACESET_H
|
||||
#define SG_FACESET_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
|
||||
class SGCOLORS;
|
||||
class SGCOORDS;
|
||||
class SGNORMALS;
|
||||
class SGCOLORINDEX;
|
||||
class SGCOORDINDEX;
|
||||
|
||||
/**
|
||||
* Define an indexed face set for a scenegraph.
|
||||
*/
|
||||
class SGFACESET : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGFACESET( SGNODE* aParent );
|
||||
virtual ~SGFACESET();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
bool CalcNormals( SGNODE** aPtr );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
/**
|
||||
* Add all internal coordinate indices to the given list in preparation for a normals
|
||||
* calculation.
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
// validate the data held by this face set
|
||||
bool validate( void );
|
||||
|
||||
// owned objects
|
||||
SGCOLORS* m_Colors;
|
||||
SGCOORDS* m_Coords;
|
||||
SGCOORDINDEX* m_CoordIndices;
|
||||
SGNORMALS* m_Normals;
|
||||
|
||||
// referenced objects
|
||||
SGCOLORS* m_RColors;
|
||||
SGCOORDS* m_RCoords;
|
||||
SGNORMALS* m_RNormals;
|
||||
|
||||
private:
|
||||
bool valid;
|
||||
bool validated;
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
p.88
|
||||
IndexedFaceSet {
|
||||
color NULL
|
||||
coord NULL
|
||||
normal NULL
|
||||
texCoord NULL
|
||||
ccw TRUE
|
||||
colorIndex []
|
||||
colorPerVertex TRUE
|
||||
convex TRUE
|
||||
coordIndex []
|
||||
creaseAngle 0
|
||||
normalIndex []
|
||||
normalPerVertex TRUE
|
||||
solid TRUE
|
||||
texCoordIndex []
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SG_FACESET_H
|
||||
@@ -1,490 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
|
||||
void S3D::FormatFloat( std::string& result, double value )
|
||||
{
|
||||
if( value < 1e-8 && value > -1e-8 )
|
||||
{
|
||||
result = "0";
|
||||
return;
|
||||
}
|
||||
|
||||
// note: many VRML implementations use float so we use the max.
|
||||
// precision here of 8 digits.
|
||||
std::ostringstream out;
|
||||
out << std::setprecision( 8 ) << value;
|
||||
|
||||
result = out.str();
|
||||
|
||||
size_t p = result.find( '.' );
|
||||
|
||||
// trim trailing 0 if appropriate
|
||||
if( std::string::npos == p )
|
||||
return;
|
||||
|
||||
p = result.find_first_of( "eE" );
|
||||
|
||||
if( std::string::npos == p )
|
||||
{
|
||||
while( '0' == *( result.rbegin() ) )
|
||||
result.erase( result.size() - 1 );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( '0' != result.at( p - 1 ) )
|
||||
return;
|
||||
|
||||
// trim all 0 to the left of 'p'
|
||||
std::string tmp = result.substr( p );
|
||||
result = result.substr( 0, p );
|
||||
|
||||
while( '0' == *( result.rbegin() ) )
|
||||
result.erase( result.size() - 1 );
|
||||
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
|
||||
{
|
||||
double aX;
|
||||
double aY;
|
||||
double aZ;
|
||||
|
||||
axis.GetVector( aX, aY, aZ );
|
||||
FormatFloat( result, aX );
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, aY );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
FormatFloat( tmp, aZ );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
FormatFloat( tmp, rotation );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatPoint( std::string& result, const SGPOINT& point )
|
||||
{
|
||||
FormatFloat( result, point.x );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, point.y );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, point.z );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
|
||||
{
|
||||
double X, Y, Z;
|
||||
aVector.GetVector( X, Y, Z );
|
||||
FormatFloat( result, X );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, Y );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, Z );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
|
||||
{
|
||||
float R, G, B;
|
||||
aColor.GetColor( R, G, B );
|
||||
FormatFloat( result, R );
|
||||
|
||||
std::string tmp;
|
||||
FormatFloat( tmp, G );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
|
||||
FormatFloat( tmp, B );
|
||||
result.append( " " );
|
||||
result.append( tmp );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WritePoint( std::ostream& aFile, const SGPOINT& aPoint )
|
||||
{
|
||||
aFile.write( (char*) &aPoint.x, sizeof( aPoint.x ) );
|
||||
aFile.write( (char*) &aPoint.y, sizeof( aPoint.y ) );
|
||||
aFile.write( (char*) &aPoint.z, sizeof( aPoint.z ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteVector( std::ostream& aFile, const SGVECTOR& aVector )
|
||||
{
|
||||
double x, y, z;
|
||||
aVector.GetVector( x, y, z );
|
||||
aFile.write( (char*) &x, sizeof( double ) );
|
||||
aFile.write( (char*) &y, sizeof( double ) );
|
||||
aFile.write( (char*) &z, sizeof( double ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::WriteColor( std::ostream& aFile, const SGCOLOR& aColor )
|
||||
{
|
||||
float r, g, b;
|
||||
aColor.GetColor( r, g, b );
|
||||
aFile.write( (char*) &r, sizeof( float ) );
|
||||
aFile.write( (char*) &g, sizeof( float ) );
|
||||
aFile.write( (char*) &b, sizeof( float ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
|
||||
{
|
||||
char schar;
|
||||
aFile.get( schar );
|
||||
|
||||
if( '[' != schar )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; missing left bracket at "
|
||||
"position %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<int>( aFile.tellg() ) );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
aFile.get( schar );
|
||||
|
||||
while( ']' != schar && aFile.good() )
|
||||
{
|
||||
name.push_back( schar );
|
||||
aFile.get( schar );
|
||||
}
|
||||
|
||||
if( schar != ']' )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; could not find right "
|
||||
"bracket" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
aName = name;
|
||||
size_t upos = name.find( '_' );
|
||||
|
||||
if( std::string::npos == upos )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no underscore in name '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
name = name.substr( 0, upos );
|
||||
S3D::SGTYPES types[S3D::SGTYPE_END] = {
|
||||
SGTYPE_TRANSFORM,
|
||||
SGTYPE_APPEARANCE,
|
||||
SGTYPE_COLORS,
|
||||
SGTYPE_COLORINDEX,
|
||||
SGTYPE_FACESET,
|
||||
SGTYPE_COORDS,
|
||||
SGTYPE_COORDINDEX,
|
||||
SGTYPE_NORMALS,
|
||||
SGTYPE_SHAPE
|
||||
};
|
||||
|
||||
for( int i = 0; i < S3D::SGTYPE_END; ++i )
|
||||
{
|
||||
if( !name.compare( S3D::GetNodeTypeName( types[i] ) ) )
|
||||
return types[i];
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; no node type matching '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
|
||||
{
|
||||
aFile.read( (char*) &aPoint.x, sizeof( aPoint.x ) );
|
||||
aFile.read( (char*) &aPoint.y, sizeof( aPoint.y ) );
|
||||
aFile.read( (char*) &aPoint.z, sizeof( aPoint.z ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
|
||||
{
|
||||
double x, y, z;
|
||||
aFile.read( (char*) &x, sizeof( double ) );
|
||||
aFile.read( (char*) &y, sizeof( double ) );
|
||||
aFile.read( (char*) &z, sizeof( double ) );
|
||||
aVector.SetVector( x, y, z );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
|
||||
{
|
||||
float r, g, b;
|
||||
aFile.read( (char*) &r, sizeof( float ) );
|
||||
aFile.read( (char*) &g, sizeof( float ) );
|
||||
aFile.read( (char*) &b, sizeof( float ) );
|
||||
aColor.SetColor( r, g, b );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::degenerate( glm::dvec3* pts ) noexcept
|
||||
{
|
||||
double dx, dy, dz;
|
||||
|
||||
dx = pts[1].x - pts[0].x;
|
||||
dy = pts[1].y - pts[0].y;
|
||||
dz = pts[1].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[0].x;
|
||||
dy = pts[2].y - pts[0].y;
|
||||
dz = pts[2].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[1].x;
|
||||
dy = pts[2].y - pts[1].y;
|
||||
dz = pts[2].z - pts[1].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
|
||||
{
|
||||
if( S3D::degenerate( pts ) )
|
||||
{
|
||||
// degenerate points should contribute nothing to the result
|
||||
tri = glm::dvec3( 0.0, 0.0, 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// normal * 2 * area
|
||||
tri = glm::cross( pts[1] - pts[0], pts[2] - pts[0] );
|
||||
}
|
||||
|
||||
|
||||
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
|
||||
std::vector< SGVECTOR >& norms )
|
||||
{
|
||||
size_t vsize = coords.size();
|
||||
|
||||
if( vsize < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid vertex set (fewer than 3 "
|
||||
"vertices)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t isize = index.size();
|
||||
|
||||
if( 0 != isize % 3 || index.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] invalid index set (not multiple of 3)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !norms.empty() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] normals set is not empty" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >vmap;
|
||||
|
||||
int p1, p2, p3;
|
||||
|
||||
// create the map of indices to facet sets
|
||||
for( size_t i = 0; i < isize; )
|
||||
{
|
||||
p1 = index[i++];
|
||||
p2 = index[i++];
|
||||
p3 = index[i++];
|
||||
|
||||
if( p1 < 0 || p1 >= (int)vsize || p2 < 0 || p2 >= (int)vsize || p3 < 0 || p3 >= (int)vsize )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::ostringstream ostr;
|
||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
ostr << " * [INFO] invalid index set; index out of bounds";
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s\n" ), ostr.str().c_str() );
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::dvec3 tri;
|
||||
glm::dvec3 trip[3];
|
||||
trip[0] = glm::dvec3( coords[p1].x, coords[p1].y, coords[p1].z );
|
||||
trip[1] = glm::dvec3( coords[p2].x, coords[p2].y, coords[p2].z );
|
||||
trip[2] = glm::dvec3( coords[p3].x, coords[p3].y, coords[p3].z );
|
||||
calcTriad( trip, tri );
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator ip = vmap.find( p1 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p1, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p2, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p3 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.emplace( p3, std::list < glm::dvec3 >( 1, tri ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator sM = vmap.begin();
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator eM = vmap.end();
|
||||
size_t idx = 0;
|
||||
|
||||
while( sM != eM )
|
||||
{
|
||||
size_t item = sM->first;
|
||||
|
||||
// assign any skipped coordinates a normal of (0,0,1)
|
||||
while( item > idx )
|
||||
{
|
||||
norms.emplace_back( 0, 0, 1 );
|
||||
++idx;
|
||||
}
|
||||
|
||||
std::list< glm::dvec3 >::iterator sT = sM->second.begin();
|
||||
std::list< glm::dvec3 >::iterator eT = sM->second.end();
|
||||
glm::dvec3 norm( 0.0, 0.0, 0.0 );
|
||||
|
||||
while( sT != eT )
|
||||
{
|
||||
norm += *sT;
|
||||
++sT;
|
||||
}
|
||||
|
||||
norms.emplace_back( norm.x, norm.y, norm.z );
|
||||
|
||||
++idx;
|
||||
++sM;
|
||||
}
|
||||
|
||||
if( norms.size() != coords.size() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] number of normals does not equal number "
|
||||
"of vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_helpers.h
|
||||
*
|
||||
* Define a number of macros to aid in repetitious code which is probably best expressed
|
||||
* as a preprocessor macro rather than as a template. This header also declares a number
|
||||
* of functions which are only of use within the sg_* classes.
|
||||
*/
|
||||
|
||||
#ifndef SG_HELPERS_H
|
||||
#define SG_HELPERS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
#include "plugins/3dapi/sg_types.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class SGNORMALS;
|
||||
class SGCOORDS;
|
||||
class SGCOORDINDEX;
|
||||
|
||||
|
||||
// Function to drop references within an SGNODE
|
||||
// The node being destroyed must remove itself from the object reference's
|
||||
// backpointer list in order to avoid a segfault.
|
||||
#define DROP_REFS( aType, aList ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL = aList.begin(); \
|
||||
std::vector<aType*>::iterator eL = aList.end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
( (SGNODE*) *sL )->delNodeRef( this ); \
|
||||
++sL; \
|
||||
} \
|
||||
aList.clear(); \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to delete owned objects within an SGNODE
|
||||
// The owned object's parent is set to NULL before
|
||||
// deletion to avoid a redundant 'unlinkChildNode' call.
|
||||
#define DEL_OBJS( aType, aList ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL = aList.begin(); \
|
||||
std::vector<aType*>::iterator eL = aList.end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
( (SGNODE*) *sL )->SetParent( nullptr, false ); \
|
||||
delete *sL; \
|
||||
++sL; \
|
||||
} \
|
||||
aList.clear(); \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to unlink a child or reference node when that child or
|
||||
// reference node is being destroyed.
|
||||
#define UNLINK_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
|
||||
do \
|
||||
{ \
|
||||
if( aNodeID == aNode->GetNodeType() ) \
|
||||
{ \
|
||||
std::vector<aType*>* oSL; \
|
||||
std::vector<aType*>::iterator sL; \
|
||||
std::vector<aType*>::iterator eL; \
|
||||
if( isChild ) \
|
||||
{ \
|
||||
oSL = &aOwnedList; \
|
||||
sL = oSL->begin(); \
|
||||
eL = oSL->end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sL == aNode ) \
|
||||
{ \
|
||||
oSL->erase( sL ); \
|
||||
return; \
|
||||
} \
|
||||
++sL; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
oSL = &aRefList; \
|
||||
sL = oSL->begin(); \
|
||||
eL = oSL->end(); \
|
||||
while( sL != eL ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sL == aNode ) \
|
||||
{ \
|
||||
delNodeRef( this ); \
|
||||
oSL->erase( sL ); \
|
||||
return; \
|
||||
} \
|
||||
++sL; \
|
||||
} \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to check a node type, check for an existing reference,
|
||||
// and add the node type to the reference list if applicable
|
||||
#define ADD_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) \
|
||||
do \
|
||||
{ \
|
||||
if( aNodeID == aNode->GetNodeType() ) \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sL; \
|
||||
sL = std::find( aOwnedList.begin(), aOwnedList.end(), aNode ); \
|
||||
if( sL != aOwnedList.end() ) \
|
||||
return true; \
|
||||
sL = std::find( aRefList.begin(), aRefList.end(), aNode ); \
|
||||
if( sL != aRefList.end() ) \
|
||||
return true; \
|
||||
if( isChild ) \
|
||||
{ \
|
||||
SGNODE* ppn = (SGNODE*) aNode->GetParent(); \
|
||||
if( nullptr != ppn ) \
|
||||
{ \
|
||||
if( this != ppn ) \
|
||||
{ \
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
||||
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
||||
std::cerr << "' has multiple parents '" << ppn->GetName() << "', '"; \
|
||||
std::cerr << m_Name << "'\n"; \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
aOwnedList.push_back( (aType*) aNode ); \
|
||||
aNode->SetParent( this, false ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/*if( nullptr == aNode->GetParent() ) { \
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
||||
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
||||
std::cerr << "' has no parent\n"; \
|
||||
std::cerr << " * [INFO] possible copy assignment or copy constructor bug\n"; \
|
||||
return false; \
|
||||
} */ \
|
||||
aRefList.push_back( (aType*) aNode ); \
|
||||
aNode->addNodeRef( this ); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
// Function to find a node object given a (non-unique) node name
|
||||
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) \
|
||||
do \
|
||||
{ \
|
||||
std::vector<aType*>::iterator sLA = aNodeList.begin(); \
|
||||
std::vector<aType*>::iterator eLA = aNodeList.end(); \
|
||||
SGNODE* psg = nullptr; \
|
||||
while( sLA != eLA ) \
|
||||
{ \
|
||||
if( (SGNODE*) *sLA != aCallingNode ) \
|
||||
{ \
|
||||
psg = (SGNODE*) ( *sLA )->FindNode( aName, this ); \
|
||||
if( nullptr != psg ) \
|
||||
return psg; \
|
||||
} \
|
||||
++sLA; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
|
||||
namespace S3D
|
||||
{
|
||||
bool degenerate( glm::dvec3* pts ) noexcept;
|
||||
|
||||
//
|
||||
// Normals calculations from triangles
|
||||
//
|
||||
|
||||
/*
|
||||
* Take an array of 3D coordinates and its corresponding index set and calculates
|
||||
* the normals assuming that indices are given in CCW order.
|
||||
*
|
||||
* Care must be taken in using this function to ensure that:
|
||||
* -# All coordinates are indexed; unindexed coordinates are assigned normal(0,0,1);
|
||||
* when dealing with VRML models which may list and reuse one large coordinate set it
|
||||
* is necessary to gather all index sets and perform this operation only once.
|
||||
* -# Index sets must represent triangles (multiple of 3 indices) and must not be
|
||||
* degenerate, that is all indices and coordinates in a triad must be unique.
|
||||
*
|
||||
* @param coords is the array of 3D vertices.
|
||||
* @param index is the array of 3x vertex indices (triads).
|
||||
* @param norms is an empty array which holds the normals corresponding to each vector.
|
||||
* @return true on success; otherwise false.
|
||||
*/
|
||||
bool CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
|
||||
std::vector< SGVECTOR >& norms );
|
||||
|
||||
// formats a floating point number for text output to a VRML file
|
||||
void FormatFloat( std::string& result, double value );
|
||||
|
||||
// format orientation data for VRML output
|
||||
void FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation );
|
||||
|
||||
// format point data for VRML output
|
||||
void FormatPoint( std::string& result, const SGPOINT& point );
|
||||
|
||||
// format vector data for VRML output
|
||||
void FormatVector( std::string& result, const SGVECTOR& aVector );
|
||||
|
||||
// format Color data for VRML output
|
||||
void FormatColor( std::string& result, const SGCOLOR& aColor );
|
||||
|
||||
//
|
||||
// Cache related WRITE functions
|
||||
//
|
||||
|
||||
// write out an XYZ vertex
|
||||
bool WritePoint( std::ostream& aFile, const SGPOINT& aPoint );
|
||||
|
||||
// write out a unit vector
|
||||
bool WriteVector( std::ostream& aFile, const SGVECTOR& aVector );
|
||||
|
||||
// write out an RGB color
|
||||
bool WriteColor( std::ostream& aFile, const SGCOLOR& aColor );
|
||||
|
||||
/**
|
||||
* Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
|
||||
*
|
||||
* @param aFile is a binary file open for reading.
|
||||
* @param aName will hold the tag name on successful return.
|
||||
* @return will be the NodeType which the tag represents or S3D::SGTYPES::SGTYPE_END on
|
||||
* failure.
|
||||
*/
|
||||
S3D::SGTYPES ReadTag( std::istream& aFile, std::string& aName );
|
||||
|
||||
// read an XYZ vertex
|
||||
bool ReadPoint( std::istream& aFile, SGPOINT& aPoint );
|
||||
|
||||
// read a unit vector
|
||||
bool ReadVector( std::istream& aFile, SGVECTOR& aVector );
|
||||
|
||||
// read an RGB color
|
||||
bool ReadColor( std::istream& aFile, SGCOLOR& aColor );
|
||||
}
|
||||
|
||||
#endif // SG_HELPERS_H
|
||||
@@ -1,329 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_index.h"
|
||||
|
||||
|
||||
SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGINDEX (type "
|
||||
"'%d')" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGINDEX::~SGINDEX()
|
||||
{
|
||||
index.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGINDEX and derived types
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
// Node should have no children or refs.
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
|
||||
{
|
||||
if( index.empty() )
|
||||
{
|
||||
nIndices = 0;
|
||||
aIndexList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
nIndices = index.size();
|
||||
aIndexList = & index[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
|
||||
{
|
||||
index.clear();
|
||||
|
||||
if( 0 == nIndices || nullptr == aIndexList )
|
||||
return;
|
||||
|
||||
for( size_t i = 0; i < nIndices; ++i )
|
||||
index.push_back( aIndexList[i] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::AddIndex( int aIndex )
|
||||
{
|
||||
index.push_back( aIndex );
|
||||
}
|
||||
|
||||
|
||||
void SGINDEX::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( index.empty() )
|
||||
return false;
|
||||
|
||||
if( S3D::SGTYPE_COORDINDEX == m_SGtype )
|
||||
return writeCoordIndex( aFile );
|
||||
|
||||
return writeColorIndex( aFile );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeCoordIndex( std::ostream& aFile )
|
||||
{
|
||||
size_t n = index.size();
|
||||
|
||||
wxCHECK_MSG( n % 3 == 0, false, wxT( "Coordinate index is not divisible by three (violates "
|
||||
"triangle constraint)" ) );
|
||||
|
||||
aFile << " coordIndex [\n ";
|
||||
|
||||
// indices to control formatting
|
||||
int nv0 = 0;
|
||||
int nv1 = 0;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
aFile << index[i];
|
||||
++i;
|
||||
|
||||
if( ++nv0 == 3 )
|
||||
{
|
||||
aFile << ",-1";
|
||||
++nv1;
|
||||
nv0 = 0;
|
||||
}
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nv1 == 8 )
|
||||
{
|
||||
nv1 = 0;
|
||||
aFile << "\n ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeColorIndex( std::ostream& aFile )
|
||||
{
|
||||
aFile << " colorIndex [\n ";
|
||||
return writeIndexList( aFile );
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::writeIndexList( std::ostream& aFile )
|
||||
{
|
||||
// index to control formatting
|
||||
int nv = 0;
|
||||
size_t n = index.size();
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
aFile << index[i];
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( ++nv == 20 )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = index.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
aFile.write( (char*)&index[i], sizeof(int) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( index.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*)&npts, sizeof(size_t) );
|
||||
int tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
aFile.read( (char*) &tmp, sizeof( int ) );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
index.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_index.h
|
||||
*/
|
||||
|
||||
#ifndef SG_INDEX_H
|
||||
#define SG_INDEX_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define a generic index interface for a scenegraph object.
|
||||
*/
|
||||
class SGINDEX : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGINDEX( SGNODE* aParent );
|
||||
virtual ~SGINDEX();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aCaller ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aCaller ) noexcept override;
|
||||
|
||||
/**
|
||||
* Retrieve the number of indices and a pointer to the list.
|
||||
*
|
||||
* @note The returned pointer may be invalidated by future operations on the SGNODE. The
|
||||
* caller must make immediate use of the data and must not rely on the pointer's
|
||||
* validity in the future.
|
||||
*
|
||||
* @param nIndices will hold the number of indices in the list.
|
||||
* @param aIndexList will store a pointer to the data.
|
||||
* @return true if there was available data (nIndices > 0) otherwise false.
|
||||
*/
|
||||
bool GetIndices( size_t& nIndices, int*& aIndexList );
|
||||
|
||||
/**
|
||||
* Set the number of indices and creates a copy of the given index data.
|
||||
*
|
||||
* @param nIndices the number of indices to be stored.
|
||||
* @param aIndexList the index data.
|
||||
*/
|
||||
void SetIndices( size_t nIndices, int* aIndexList );
|
||||
|
||||
|
||||
/**
|
||||
* Add a single index to the list.
|
||||
*
|
||||
* @param aIndex is the index to add.
|
||||
*/
|
||||
void AddIndex( int aIndex );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
protected:
|
||||
bool writeCoordIndex( std::ostream& aFile );
|
||||
bool writeColorIndex( std::ostream& aFile );
|
||||
bool writeIndexList( std::ostream& aFile );
|
||||
|
||||
public:
|
||||
// for internal SG consumption only
|
||||
std::vector< int > index;
|
||||
};
|
||||
|
||||
#endif // SG_INDEX_H
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
|
||||
|
||||
static const std::string node_names[S3D::SGTYPE_END + 1] = {
|
||||
"TXFM",
|
||||
"APP",
|
||||
"COL",
|
||||
"COLIDX",
|
||||
"FACE",
|
||||
"COORD",
|
||||
"COORDIDX",
|
||||
"NORM",
|
||||
"SHAPE",
|
||||
"INVALID"
|
||||
};
|
||||
|
||||
|
||||
static unsigned int node_counts[S3D::SGTYPE_END] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
|
||||
char const* S3D::GetNodeTypeName( S3D::SGTYPES aType ) noexcept
|
||||
{
|
||||
return node_names[aType].c_str();
|
||||
}
|
||||
|
||||
|
||||
static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
|
||||
{
|
||||
if( nodeType < 0 || nodeType >= S3D::SGTYPE_END )
|
||||
{
|
||||
aName = node_names[S3D::SGTYPE_END];
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int seqNum = node_counts[nodeType];
|
||||
++node_counts[nodeType];
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << node_names[nodeType] << "_" << seqNum;
|
||||
aName = ostr.str();
|
||||
}
|
||||
|
||||
|
||||
SGNODE::SGNODE( SGNODE* aParent )
|
||||
{
|
||||
m_Parent = aParent;
|
||||
m_Association = nullptr;
|
||||
m_written = false;
|
||||
m_SGtype = S3D::SGTYPE_END;
|
||||
}
|
||||
|
||||
|
||||
SGNODE::~SGNODE()
|
||||
{
|
||||
if( m_Parent )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
if( m_Association )
|
||||
*m_Association = nullptr;
|
||||
|
||||
std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
|
||||
std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
|
||||
|
||||
while( sBP != eBP )
|
||||
{
|
||||
(*sBP)->unlinkRefNode( this );
|
||||
++sBP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S3D::SGTYPES SGNODE::GetNodeType( void ) const noexcept
|
||||
{
|
||||
return m_SGtype;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGNODE::GetParent( void ) const noexcept
|
||||
{
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
|
||||
bool SGNODE::SwapParent( SGNODE* aNewParent )
|
||||
{
|
||||
if( aNewParent == m_Parent )
|
||||
return true;
|
||||
|
||||
if( nullptr == aNewParent )
|
||||
return false;
|
||||
|
||||
if( nullptr == m_Parent )
|
||||
{
|
||||
if( aNewParent->AddChildNode( this ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aNewParent->GetNodeType() != m_Parent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
SGNODE* oldParent = m_Parent;
|
||||
m_Parent->unlinkChildNode( this );
|
||||
m_Parent = nullptr;
|
||||
aNewParent->unlinkRefNode( this );
|
||||
aNewParent->AddChildNode( this );
|
||||
oldParent->AddRefNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char* SGNODE::GetName( void )
|
||||
{
|
||||
if( m_Name.empty() )
|
||||
getNodeName( m_SGtype, m_Name );
|
||||
|
||||
return m_Name.c_str();
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::SetName( const char* aName )
|
||||
{
|
||||
if( nullptr == aName || 0 == aName[0] )
|
||||
getNodeName( m_SGtype, m_Name );
|
||||
else
|
||||
m_Name = aName;
|
||||
}
|
||||
|
||||
|
||||
const char* SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept
|
||||
{
|
||||
return node_names[aNodeType].c_str();
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::addNodeRef( SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
std::list< SGNODE* >::iterator np =
|
||||
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
|
||||
|
||||
if( np != m_BackPointers.end() )
|
||||
return;
|
||||
|
||||
m_BackPointers.push_back( aNode );
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::delNodeRef( const SGNODE* aNode )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
std::list< SGNODE* >::iterator np =
|
||||
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
|
||||
|
||||
if( np != m_BackPointers.end() )
|
||||
{
|
||||
m_BackPointers.erase( np );
|
||||
return;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] delNodeRef() did not find its target, this "
|
||||
"node type %d, referenced node type %d" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
m_SGtype,
|
||||
aNode->GetNodeType() );
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef ) noexcept
|
||||
{
|
||||
wxCHECK( aWrapperRef && *aWrapperRef == this, /* void */ );
|
||||
|
||||
// if there is an existing association then break it and emit a warning
|
||||
// just in case the behavior is undesired
|
||||
if( m_Association )
|
||||
{
|
||||
*m_Association = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [WARNING] association being broken with "
|
||||
"previous wrapper" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
m_Association = aWrapperRef;
|
||||
}
|
||||
|
||||
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef ) noexcept
|
||||
{
|
||||
if( !m_Association )
|
||||
return;
|
||||
|
||||
wxCHECK( aWrapperRef, /* void */ );
|
||||
|
||||
wxCHECK( *aWrapperRef == *m_Association && aWrapperRef == m_Association, /* void */ );
|
||||
|
||||
m_Association = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGNODE::ResetNodeIndex( void ) noexcept
|
||||
{
|
||||
for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
|
||||
node_counts[i] = 1;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
|
||||
{
|
||||
aIndex = 0;
|
||||
|
||||
wxCHECK( aNode && S3D::SGTYPE_APPEARANCE == aNode->GetNodeType(), false );
|
||||
|
||||
SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
|
||||
|
||||
std::map< SGAPPEARANCE const*, int >::iterator it = aList.matmap.find( node );
|
||||
|
||||
if( it != aList.matmap.end() )
|
||||
{
|
||||
aIndex = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
int idx = (int)aList.matorder.size();
|
||||
aList.matorder.push_back( node );
|
||||
aList.matmap.emplace( node, idx );
|
||||
aIndex = idx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
|
||||
{
|
||||
aMaterial = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_SMESH( SMESH& aMesh ) noexcept
|
||||
{
|
||||
aMesh = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::INIT_S3DMODEL( S3DMODEL& aModel ) noexcept
|
||||
{
|
||||
aModel = {};
|
||||
}
|
||||
|
||||
|
||||
void S3D::FREE_SMESH( SMESH& aMesh ) noexcept
|
||||
{
|
||||
if( nullptr != aMesh.m_Positions )
|
||||
{
|
||||
delete [] aMesh.m_Positions;
|
||||
aMesh.m_Positions = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Normals )
|
||||
{
|
||||
delete [] aMesh.m_Normals;
|
||||
aMesh.m_Normals = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Texcoords )
|
||||
{
|
||||
delete [] aMesh.m_Texcoords;
|
||||
aMesh.m_Texcoords = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_Color )
|
||||
{
|
||||
delete [] aMesh.m_Color;
|
||||
aMesh.m_Color = nullptr;
|
||||
}
|
||||
|
||||
if( nullptr != aMesh.m_FaceIdx )
|
||||
{
|
||||
delete [] aMesh.m_FaceIdx;
|
||||
aMesh.m_FaceIdx = nullptr;
|
||||
}
|
||||
|
||||
aMesh.m_VertexSize = 0;
|
||||
aMesh.m_FaceIdxSize = 0;
|
||||
aMesh.m_MaterialIdx = 0;
|
||||
}
|
||||
|
||||
|
||||
void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
|
||||
{
|
||||
if( nullptr != aModel.m_Materials )
|
||||
{
|
||||
delete [] aModel.m_Materials;
|
||||
aModel.m_Materials = nullptr;
|
||||
}
|
||||
|
||||
aModel.m_MaterialsSize = 0;
|
||||
|
||||
if( nullptr != aModel.m_Meshes )
|
||||
{
|
||||
for( unsigned int i = 0; i < aModel.m_MeshesSize; ++i )
|
||||
FREE_SMESH( aModel.m_Meshes[i] );
|
||||
|
||||
delete [] aModel.m_Meshes;
|
||||
aModel.m_Meshes = nullptr;
|
||||
}
|
||||
|
||||
aModel.m_MeshesSize = 0;
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_node.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_NODE_H
|
||||
#define SG_NODE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "plugins/3dapi/c3dmodel.h"
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
#include "plugins/3dapi/sg_types.h"
|
||||
|
||||
class SGNODE;
|
||||
class SGAPPEARANCE;
|
||||
|
||||
namespace S3D
|
||||
{
|
||||
/**
|
||||
* Return the name of the given type of node
|
||||
*/
|
||||
char const* GetNodeTypeName( S3D::SGTYPES aType ) noexcept;
|
||||
|
||||
struct MATLIST
|
||||
{
|
||||
std::vector< SGAPPEARANCE const* > matorder; // materials in order of addition
|
||||
std::map< SGAPPEARANCE const*, int > matmap; // mapping from material to index
|
||||
};
|
||||
|
||||
bool GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex );
|
||||
|
||||
void INIT_SMATERIAL( SMATERIAL& aMaterial );
|
||||
void INIT_SMESH( SMESH& aMesh ) noexcept;
|
||||
void INIT_S3DMODEL( S3DMODEL& aModel ) noexcept;
|
||||
|
||||
void FREE_SMESH( SMESH& aMesh) noexcept;
|
||||
void FREE_S3DMODEL( S3DMODEL& aModel );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The base class of all Scene Graph nodes.
|
||||
*/
|
||||
class SGNODE
|
||||
{
|
||||
public:
|
||||
SGNODE( SGNODE* aParent );
|
||||
virtual ~SGNODE();
|
||||
|
||||
/**
|
||||
* Return the type of this node instance.
|
||||
*/
|
||||
S3D::SGTYPES GetNodeType( void ) const noexcept;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the parent SGNODE of this object or NULL if the object has
|
||||
* no parent (ie. top level transform).
|
||||
*/
|
||||
SGNODE* GetParent( void ) const noexcept;
|
||||
|
||||
/**
|
||||
* Set the parent #SGNODE of this object.
|
||||
*
|
||||
* @param aParent [in] is the desired parent node
|
||||
* @return true if the operation succeeds; false if the given node is not allowed to
|
||||
* be a parent to the derived object.
|
||||
*/
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) = 0;
|
||||
|
||||
/**
|
||||
* Swap the ownership with the given parent.
|
||||
*
|
||||
* This operation may be required when reordering nodes for optimization.
|
||||
*
|
||||
* @param aNewParent will become the new parent to the object; it must be the same type
|
||||
* as the parent of this instance.
|
||||
*/
|
||||
bool SwapParent( SGNODE* aNewParent );
|
||||
|
||||
const char* GetName( void );
|
||||
void SetName(const char *aName);
|
||||
|
||||
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const noexcept;
|
||||
|
||||
/**
|
||||
* Search the tree of linked nodes and return a reference to the first node found with
|
||||
* the given name.
|
||||
*
|
||||
* The reference is then typically added to another node via AddRefNode().
|
||||
*
|
||||
* @param aNodeName is the name of the node to search for.
|
||||
* @param aCaller is a pointer to the node invoking this function.
|
||||
* @return is a valid node pointer on success, otherwise NULL.
|
||||
*/
|
||||
virtual SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller ) = 0;
|
||||
|
||||
virtual bool AddRefNode( SGNODE* aNode ) = 0;
|
||||
|
||||
virtual bool AddChildNode( SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Associate this object with a handle to itself.
|
||||
*
|
||||
* The handle is typically held by an IFSG* wrapper and the pointer which it refers to
|
||||
* is set to NULL upon destruction of this object. This mechanism provides a scheme
|
||||
* by which a wrapper can be notified of the destruction of the object which it wraps.
|
||||
*/
|
||||
void AssociateWrapper( SGNODE** aWrapperRef ) noexcept;
|
||||
|
||||
/**
|
||||
* Remove the association between an IFSG* wrapper object and this object.
|
||||
*/
|
||||
void DisassociateWrapper( SGNODE** aWrapperRef ) noexcept;
|
||||
|
||||
/**
|
||||
* Reset the global SG* node indices in preparation for write operations.
|
||||
*/
|
||||
void ResetNodeIndex( void ) noexcept;
|
||||
|
||||
/**
|
||||
* Rename a node and all its child nodes in preparation for write operations.
|
||||
*/
|
||||
virtual void ReNameNodes( void ) = 0;
|
||||
|
||||
/**
|
||||
* Writes this node's data to a VRML file.
|
||||
*
|
||||
* This includes all data of child and referenced nodes.
|
||||
*/
|
||||
virtual bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) = 0;
|
||||
|
||||
/**
|
||||
* Write this node's data to a binary cache file.
|
||||
*
|
||||
* The data includes all data of children and references to children. If this function
|
||||
* is invoked by the user, parentNode must be set to NULL in order to ensure coherent data.
|
||||
*/
|
||||
virtual bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) = 0;
|
||||
|
||||
/**
|
||||
* Reads binary format data from a cache file.
|
||||
*
|
||||
* To read a cache file, open the file for reading and invoke this function from a new
|
||||
* #SCENEGRAPH node.
|
||||
*/
|
||||
virtual bool ReadCache( std::istream& aFile, SGNODE* parentNode ) = 0;
|
||||
|
||||
/**
|
||||
* Remove references to an owned child.
|
||||
*
|
||||
* This is invoked by the child upon destruction to ensure that the parent has no
|
||||
* invalid references.
|
||||
*
|
||||
* @param aNode is the child which is being deleted.
|
||||
*/
|
||||
virtual void unlinkChildNode( const SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Remove pointers to a referenced node.
|
||||
*
|
||||
* This is invoked by the referenced node upon destruction to ensure that the referring
|
||||
* node has no invalid references.
|
||||
*
|
||||
* @param aNode is the node which is being deleted.
|
||||
*/
|
||||
virtual void unlinkRefNode( const SGNODE* aNode ) = 0;
|
||||
|
||||
/**
|
||||
* Add a pointer to a node which references this node, but does not own.
|
||||
*
|
||||
* Such back-pointers are required to ensure that invalidated references are removed
|
||||
* when a node is deleted.
|
||||
*
|
||||
* @param aNode is the node holding a reference to this object.
|
||||
*/
|
||||
void addNodeRef( SGNODE* aNode );
|
||||
|
||||
/**
|
||||
* Remove a pointer to a node which references this node, but does not own.
|
||||
*
|
||||
* @param aNode is the node holding a reference to this object.
|
||||
*/
|
||||
void delNodeRef( const SGNODE* aNode );
|
||||
|
||||
/**
|
||||
* Return true if the object had already been written to a cache file or VRML file
|
||||
*
|
||||
* For internal use only.
|
||||
*/
|
||||
bool isWritten( void ) noexcept
|
||||
{
|
||||
return m_written;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::list< SGNODE* > m_BackPointers; ///< nodes which hold a reference to this.
|
||||
SGNODE* m_Parent; ///< Pointer to parent node; may be NULL for top level transform.
|
||||
S3D::SGTYPES m_SGtype; ///< Type of Scene Graph node.
|
||||
std::string m_Name; ///< name to use for referencing the entity by name.
|
||||
bool m_written; ///< Set to true when the object has been written after a ReNameNodes().
|
||||
|
||||
private:
|
||||
SGNODE** m_Association; ///< Handle to the instance held by a wrapper.
|
||||
};
|
||||
|
||||
#endif // SG_NODE_H
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
|
||||
|
||||
SGNORMALS::SGNORMALS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_NORMALS;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGNORMALS "
|
||||
"(type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGNORMALS::~SGNORMALS()
|
||||
{
|
||||
norms.clear();
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGFACESET may be parent to a SGNORMALS
|
||||
if( nullptr != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGNORMALS::FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller ) noexcept
|
||||
{
|
||||
wxCHECK( false, /* void */ );
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::AddRefNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::AddChildNode( SGNODE* aNode ) noexcept
|
||||
{
|
||||
wxCHECK( false, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
|
||||
{
|
||||
if( norms.empty() )
|
||||
{
|
||||
aListSize = 0;
|
||||
aNormalList = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
aListSize = norms.size();
|
||||
aNormalList = &norms[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
|
||||
{
|
||||
norms.clear();
|
||||
|
||||
if( 0 == aListSize || nullptr == aNormalList )
|
||||
return;
|
||||
|
||||
for( int i = 0; i < (int)aListSize; ++i )
|
||||
norms.push_back( aNormalList[i] );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
|
||||
{
|
||||
norms.emplace_back( aXValue, aYValue, aZValue );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::AddNormal( const SGVECTOR& aNormal )
|
||||
{
|
||||
norms.push_back( aNormal );
|
||||
}
|
||||
|
||||
|
||||
void SGNORMALS::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( norms.empty() )
|
||||
return false;
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << " normal DEF " << GetName() << " Normal { vector [\n ";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " normal USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " normal Normal { vector [\n ";
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
size_t n = norms.size();
|
||||
bool nline = false;
|
||||
|
||||
for( size_t i = 0; i < n; )
|
||||
{
|
||||
S3D::FormatVector( tmp, norms[i] );
|
||||
aFile << tmp ;
|
||||
++i;
|
||||
|
||||
if( i < n )
|
||||
{
|
||||
aFile << ",";
|
||||
|
||||
if( nline )
|
||||
{
|
||||
aFile << "\n ";
|
||||
nline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nline = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
aFile << "] }\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
size_t npts = norms.size();
|
||||
aFile.write( (char*)&npts, sizeof(size_t) );
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
S3D::WriteVector( aFile, norms[i] );
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGNORMALS::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( norms.empty(), false );
|
||||
|
||||
size_t npts;
|
||||
aFile.read( (char*) &npts, sizeof( size_t ) );
|
||||
SGVECTOR tmp;
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
for( size_t i = 0; i < npts; ++i )
|
||||
{
|
||||
if( !S3D::ReadVector( aFile, tmp ) || aFile.fail() )
|
||||
return false;
|
||||
|
||||
norms.push_back( tmp );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_normals.h
|
||||
*/
|
||||
|
||||
#ifndef SG_NORMALS_H
|
||||
#define SG_NORMALS_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
/**
|
||||
* Define a set of vertex normals for a scene graph object
|
||||
*/
|
||||
class SGNORMALS : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGNORMALS( SGNODE* aParent );
|
||||
virtual ~SGNORMALS();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode( const char* aNodeName, const SGNODE* aCaller ) noexcept override;
|
||||
bool AddRefNode( SGNODE* aNode ) noexcept override;
|
||||
bool AddChildNode( SGNODE* aNode ) noexcept override;
|
||||
|
||||
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
|
||||
void SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
|
||||
void AddNormal( double aXValue, double aYValue, double aZValue );
|
||||
void AddNormal( const SGVECTOR& aNormal );
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) noexcept override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) noexcept override;
|
||||
|
||||
std::vector< SGVECTOR > norms;
|
||||
};
|
||||
|
||||
#endif // SG_NORMALS_H
|
||||
@@ -1,783 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "3d_cache/sg/sg_shape.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
#include "3d_cache/sg/sg_appearance.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_coordindex.h"
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_colors.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
|
||||
|
||||
SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
|
||||
{
|
||||
m_SGtype = S3D::SGTYPE_SHAPE;
|
||||
m_Appearance = nullptr;
|
||||
m_RAppearance = nullptr;
|
||||
m_FaceSet = nullptr;
|
||||
m_RFaceSet = nullptr;
|
||||
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent = nullptr;
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] inappropriate parent to SGSHAPE (type %d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aParent->GetNodeType() );
|
||||
}
|
||||
else if( nullptr != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
|
||||
{
|
||||
m_Parent->AddChildNode( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SGSHAPE::~SGSHAPE()
|
||||
{
|
||||
// drop references
|
||||
if( m_RAppearance )
|
||||
{
|
||||
m_RAppearance->delNodeRef( this );
|
||||
m_RAppearance = nullptr;
|
||||
}
|
||||
|
||||
if( m_RFaceSet )
|
||||
{
|
||||
m_RFaceSet->delNodeRef( this );
|
||||
m_RFaceSet = nullptr;
|
||||
}
|
||||
|
||||
// delete objects
|
||||
if( m_Appearance )
|
||||
{
|
||||
m_Appearance->SetParent( nullptr, false );
|
||||
delete m_Appearance;
|
||||
m_Appearance = nullptr;
|
||||
}
|
||||
|
||||
if( m_FaceSet )
|
||||
{
|
||||
m_FaceSet->SetParent( nullptr, false );
|
||||
delete m_FaceSet;
|
||||
m_FaceSet = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
|
||||
{
|
||||
if( nullptr != m_Parent )
|
||||
{
|
||||
if( aParent == m_Parent )
|
||||
return true;
|
||||
|
||||
// handle the change in parents
|
||||
if( notify )
|
||||
m_Parent->unlinkChildNode( this );
|
||||
|
||||
m_Parent = nullptr;
|
||||
|
||||
if( nullptr == aParent )
|
||||
return true;
|
||||
}
|
||||
|
||||
// only a SGTRANSFORM may be parent to a SGSHAPE
|
||||
if( nullptr != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
|
||||
return false;
|
||||
|
||||
m_Parent = aParent;
|
||||
|
||||
if( m_Parent )
|
||||
m_Parent->AddChildNode( this );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SGNODE* SGSHAPE::FindNode( const char* aNodeName, const SGNODE* aCaller )
|
||||
{
|
||||
if( nullptr == aNodeName || 0 == aNodeName[0] )
|
||||
return nullptr;
|
||||
|
||||
if( !m_Name.compare( aNodeName ) )
|
||||
return this;
|
||||
|
||||
SGNODE* tmp = nullptr;
|
||||
|
||||
if( nullptr != m_Appearance )
|
||||
{
|
||||
tmp = m_Appearance->FindNode( aNodeName, this );
|
||||
|
||||
if( tmp )
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if( nullptr != m_FaceSet )
|
||||
{
|
||||
tmp = m_FaceSet->FindNode( aNodeName, this );
|
||||
|
||||
if( tmp )
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// query the parent if appropriate
|
||||
if( aCaller == m_Parent || nullptr == m_Parent )
|
||||
return nullptr;
|
||||
|
||||
return m_Parent->FindNode( aNodeName, this );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
|
||||
{
|
||||
if( nullptr == aNode )
|
||||
return;
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
if( aNode == m_Appearance )
|
||||
{
|
||||
m_Appearance = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_FaceSet )
|
||||
{
|
||||
m_FaceSet = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aNode == m_RAppearance )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RAppearance = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if( aNode == m_RFaceSet )
|
||||
{
|
||||
delNodeRef( this );
|
||||
m_RFaceSet = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
|
||||
{
|
||||
unlinkNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
|
||||
{
|
||||
wxCHECK( aNode, false );
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_Appearance || m_RAppearance )
|
||||
{
|
||||
if( aNode != m_Appearance && aNode != m_RAppearance )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Appearance "
|
||||
"nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_Appearance = (SGAPPEARANCE*)aNode;
|
||||
m_Appearance->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RAppearance = (SGAPPEARANCE*)aNode;
|
||||
m_RAppearance->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_FACESET == aNode->GetNodeType() )
|
||||
{
|
||||
if( m_FaceSet || m_RFaceSet )
|
||||
{
|
||||
if( aNode != m_FaceSet && aNode != m_RFaceSet )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple FaceSet nodes" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( isChild )
|
||||
{
|
||||
m_FaceSet = (SGFACESET*)aNode;
|
||||
m_FaceSet->SetParent( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RFaceSet = (SGFACESET*)aNode;
|
||||
m_RFaceSet->addNodeRef( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object %s is not a valid type for this "
|
||||
"object (%d)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, aNode->GetName(), aNode->GetNodeType() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::AddRefNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, false );
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::AddChildNode( SGNODE* aNode )
|
||||
{
|
||||
return addNode( aNode, true );
|
||||
}
|
||||
|
||||
|
||||
void SGSHAPE::ReNameNodes( void )
|
||||
{
|
||||
m_written = false;
|
||||
|
||||
// rename this node
|
||||
m_Name.clear();
|
||||
GetName();
|
||||
|
||||
// rename Appearance
|
||||
if( m_Appearance )
|
||||
m_Appearance->ReNameNodes();
|
||||
|
||||
// rename FaceSet
|
||||
if( m_FaceSet )
|
||||
m_FaceSet->ReNameNodes();
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
|
||||
{
|
||||
if( !m_Appearance && !m_RAppearance && !m_FaceSet && !m_RFaceSet )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aReuseFlag )
|
||||
{
|
||||
if( !m_written )
|
||||
{
|
||||
aFile << "DEF " << GetName() << " Shape {\n";
|
||||
m_written = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " USE " << GetName() << "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aFile << " Shape {\n";
|
||||
}
|
||||
|
||||
if( m_Appearance )
|
||||
m_Appearance->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RAppearance )
|
||||
m_RAppearance->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_FaceSet )
|
||||
m_FaceSet->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
if( m_RFaceSet )
|
||||
m_RFaceSet->WriteVRML( aFile, aReuseFlag );
|
||||
|
||||
aFile << "}\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
if( nullptr == parentNode )
|
||||
{
|
||||
wxCHECK( m_Parent, false );
|
||||
|
||||
SGNODE* np = m_Parent;
|
||||
|
||||
while( nullptr != np->GetParent() )
|
||||
np = np->GetParent();
|
||||
|
||||
if( np->WriteCache( aFile, nullptr ) )
|
||||
{
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxCHECK( parentNode == m_Parent, false );
|
||||
|
||||
if( !aFile.good() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] bad stream" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if any references are unwritten and swap parents if so
|
||||
if( nullptr != m_RAppearance && !m_RAppearance->isWritten() )
|
||||
m_RAppearance->SwapParent(this);
|
||||
|
||||
if( nullptr != m_RFaceSet && !m_RFaceSet->isWritten() )
|
||||
m_RFaceSet->SwapParent( this );
|
||||
|
||||
aFile << "[" << GetName() << "]";
|
||||
#define NITEMS 4
|
||||
bool items[NITEMS];
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NITEMS; ++i )
|
||||
items[i] = 0;
|
||||
|
||||
i = 0;
|
||||
|
||||
if( nullptr != m_Appearance )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_RAppearance )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_FaceSet )
|
||||
items[i] = true;
|
||||
|
||||
++i;
|
||||
|
||||
if( nullptr != m_RFaceSet )
|
||||
items[i] = true;
|
||||
|
||||
for( int jj = 0; jj < NITEMS; ++jj )
|
||||
aFile.write( (char*)&items[jj], sizeof(bool) );
|
||||
|
||||
if( items[0] )
|
||||
m_Appearance->WriteCache( aFile, this );
|
||||
|
||||
if( items[1] )
|
||||
aFile << "[" << m_RAppearance->GetName() << "]";
|
||||
|
||||
if( items[2] )
|
||||
m_FaceSet->WriteCache( aFile, this );
|
||||
|
||||
if( items[3] )
|
||||
aFile << "[" << m_RFaceSet->GetName() << "]";
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
m_written = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
|
||||
{
|
||||
wxCHECK( m_Appearance == nullptr && m_RAppearance == nullptr && m_FaceSet == nullptr &&
|
||||
m_RFaceSet == nullptr, false );
|
||||
|
||||
#define NITEMS 4
|
||||
bool items[NITEMS];
|
||||
|
||||
for( int i = 0; i < NITEMS; ++i )
|
||||
aFile.read( (char*)&items[i], sizeof(bool) );
|
||||
|
||||
if( ( items[0] && items[1] ) || ( items[2] && items[3] ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if( items[0] )
|
||||
{
|
||||
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child appearance "
|
||||
"tag at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Appearance = new SGAPPEARANCE( this );
|
||||
m_Appearance->SetName( name.c_str() );
|
||||
|
||||
if( !m_Appearance->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading appearance "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[1] )
|
||||
{
|
||||
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref appearance tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref "
|
||||
"appearance '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_APPEARANCE != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not "
|
||||
"SGAPPEARANCE '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RAppearance = (SGAPPEARANCE*)np;
|
||||
m_RAppearance->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( items[2] )
|
||||
{
|
||||
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child face set tag "
|
||||
"at position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_FaceSet = new SGFACESET( this );
|
||||
m_FaceSet->SetName( name.c_str() );
|
||||
|
||||
if( !m_FaceSet->ReadCache( aFile, this ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading face set "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, name );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( items[3] )
|
||||
{
|
||||
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref face set tag at "
|
||||
"position %ul" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
static_cast<unsigned long>( aFile.tellg() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SGNODE* np = FindNode( name.c_str(), this );
|
||||
|
||||
if( !np )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref face "
|
||||
"set '%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( S3D::SGTYPE_FACESET != np->GetNodeType() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGFACESET "
|
||||
"'%s'" ),
|
||||
__FILE__, __FUNCTION__, __LINE__,
|
||||
name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RFaceSet = (SGFACESET*)np;
|
||||
m_RFaceSet->addNodeRef( this );
|
||||
}
|
||||
|
||||
if( aFile.fail() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGSHAPE::Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes )
|
||||
{
|
||||
SMESH m;
|
||||
S3D::INIT_SMESH( m );
|
||||
|
||||
SGAPPEARANCE* pa = m_Appearance;
|
||||
SGFACESET* pf = m_FaceSet;
|
||||
|
||||
if( nullptr == pa )
|
||||
pa = m_RAppearance;
|
||||
|
||||
if( nullptr == pf )
|
||||
pf = m_RFaceSet;
|
||||
|
||||
// no face sets = nothing to render, which is valid though pointless
|
||||
if( nullptr == pf )
|
||||
return true;
|
||||
|
||||
if( !pf->validate() )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; inconsistent data" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( nullptr == pa )
|
||||
{
|
||||
m.m_MaterialIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx;
|
||||
|
||||
if( !S3D::GetMatIndex( materials, pa, idx ) )
|
||||
{
|
||||
m.m_MaterialIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m.m_MaterialIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
SGCOLORS* pc = pf->m_Colors;
|
||||
SGCOORDS* pv = pf->m_Coords;
|
||||
SGCOORDINDEX* vidx = pf->m_CoordIndices;
|
||||
SGNORMALS* pn = pf->m_Normals;
|
||||
|
||||
if( nullptr == pc )
|
||||
pc = pf->m_RColors;
|
||||
|
||||
if( nullptr == pv )
|
||||
pv = pf->m_RCoords;
|
||||
|
||||
if( nullptr == pn )
|
||||
pn = pf->m_RNormals;
|
||||
|
||||
// set the vertex points and indices
|
||||
size_t nCoords = 0;
|
||||
SGPOINT* pCoords = nullptr;
|
||||
pv->GetCoordsList( nCoords, pCoords );
|
||||
|
||||
size_t nColors = 0;
|
||||
SGCOLOR* pColors = nullptr;
|
||||
|
||||
if( pc )
|
||||
{
|
||||
// check the vertex colors
|
||||
pc->GetColorList( nColors, pColors );
|
||||
|
||||
if( nColors < nCoords )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough colors per "
|
||||
"vertex (%ul vs %ul)" ),
|
||||
__FILE__, __FUNCTION__, __LINE__, static_cast<unsigned long>( nColors ),
|
||||
static_cast<unsigned long>( nCoords ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// set the vertex indices
|
||||
size_t nvidx = 0;
|
||||
int* lv = nullptr;
|
||||
vidx->GetIndices( nvidx, lv );
|
||||
|
||||
// note: reduce the vertex set to include only the referenced vertices
|
||||
std::vector< int > vertices; // store the list of temp vertex indices
|
||||
std::map< int, unsigned int > indexmap; // map temp vertex to true vertex
|
||||
std::map< int, unsigned int >::iterator mit;
|
||||
|
||||
for( unsigned int i = 0; i < nvidx; ++i )
|
||||
{
|
||||
mit = indexmap.find( lv[i] );
|
||||
|
||||
if( mit == indexmap.end() )
|
||||
{
|
||||
indexmap.emplace( lv[i], vertices.size() );
|
||||
vertices.push_back( lv[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if( vertices.size() < 3 )
|
||||
{
|
||||
wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; not enough vertices" ),
|
||||
__FILE__, __FUNCTION__, __LINE__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// construct the final vertex/color list
|
||||
SFVEC3F* lColors = nullptr;
|
||||
SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
|
||||
int ti;
|
||||
|
||||
if( pc )
|
||||
{
|
||||
lColors = new SFVEC3F[vertices.size()];
|
||||
m.m_Color = lColors;
|
||||
}
|
||||
|
||||
if( pc )
|
||||
{
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
pColors[ti].GetColor( lColors[i].x, lColors[i].y, lColors[i].z );
|
||||
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
}
|
||||
|
||||
m.m_VertexSize = (unsigned int) vertices.size();
|
||||
m.m_Positions = lCoords;
|
||||
unsigned int* lvidx = new unsigned int[ nvidx ];
|
||||
|
||||
for( unsigned int i = 0; i < nvidx; ++i )
|
||||
{
|
||||
mit = indexmap.find( lv[i] );
|
||||
lvidx[i] = mit->second;
|
||||
}
|
||||
|
||||
m.m_FaceIdxSize = (unsigned int )nvidx;
|
||||
m.m_FaceIdx = lvidx;
|
||||
|
||||
// set the per-vertex normals
|
||||
size_t nNorms = 0;
|
||||
SGVECTOR* pNorms = nullptr;
|
||||
double x, y, z;
|
||||
|
||||
pn->GetNormalList( nNorms, pNorms );
|
||||
SFVEC3F* lNorms = new SFVEC3F[ vertices.size() ];
|
||||
|
||||
for( size_t i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
ti = vertices[i];
|
||||
pNorms[ti].GetVector( x, y, z );
|
||||
glm::dvec4 pt( x, y, z, 0.0 );
|
||||
pt = (*aTransform) * pt;
|
||||
|
||||
lNorms[i] = SFVEC3F( pt.x, pt.y, pt.z );
|
||||
}
|
||||
|
||||
m.m_Normals = lNorms;
|
||||
meshes.push_back( m );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sg_shape.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SG_SHAPE_H
|
||||
#define SG_SHAPE_H
|
||||
|
||||
#include <vector>
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
class SGAPPEARANCE;
|
||||
class SGFACESET;
|
||||
|
||||
/**
|
||||
* Define a complex 3D shape for a scenegraph object.
|
||||
*/
|
||||
class SGSHAPE : public SGNODE
|
||||
{
|
||||
public:
|
||||
SGSHAPE( SGNODE* aParent );
|
||||
virtual ~SGSHAPE();
|
||||
|
||||
virtual bool SetParent( SGNODE* aParent, bool notify = true ) override;
|
||||
|
||||
SGNODE* FindNode(const char* aNodeName, const SGNODE* aCaller) override;
|
||||
bool AddRefNode( SGNODE* aNode ) override;
|
||||
bool AddChildNode( SGNODE* aNode ) override;
|
||||
|
||||
void ReNameNodes( void ) override;
|
||||
bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
|
||||
|
||||
bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
|
||||
bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
|
||||
|
||||
bool Prepare( const glm::dmat4* aTransform, S3D::MATLIST& materials,
|
||||
std::vector< SMESH >& meshes );
|
||||
|
||||
void unlinkChildNode( const SGNODE* aNode ) override;
|
||||
void unlinkRefNode( const SGNODE* aNode ) override;
|
||||
|
||||
private:
|
||||
void unlinkNode( const SGNODE* aNode, bool isChild );
|
||||
bool addNode( SGNODE* aNode, bool isChild );
|
||||
|
||||
public:
|
||||
// owned node
|
||||
SGAPPEARANCE* m_Appearance;
|
||||
SGFACESET* m_FaceSet;
|
||||
|
||||
// referenced nodes
|
||||
SGAPPEARANCE* m_RAppearance;
|
||||
SGFACESET* m_RFaceSet;
|
||||
};
|
||||
|
||||
/*
|
||||
p.107
|
||||
Shape {
|
||||
appearance NULL
|
||||
geometry NULL
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SG_SHAPE_H
|
||||
@@ -0,0 +1,672 @@
|
||||
/**
|
||||
* @file 3d_canvas.cpp
|
||||
*/
|
||||
#include <fctsys.h>
|
||||
#include <trigo.h>
|
||||
|
||||
#include <wx/image.h>
|
||||
|
||||
#if !wxUSE_GLCANVAS
|
||||
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
|
||||
#endif
|
||||
|
||||
#include <wx/dataobj.h>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
#include <gestfich.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
#include <3d_viewer_id.h>
|
||||
|
||||
|
||||
// -----------------
|
||||
// helper function (from wxWidgets, opengl/cube.cpp sample
|
||||
// -----------------
|
||||
void CheckGLError()
|
||||
{
|
||||
GLenum errLast = GL_NO_ERROR;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if ( err == GL_NO_ERROR )
|
||||
return;
|
||||
|
||||
// normally the error is reset by the call to glGetError() but if
|
||||
// glGetError() itself returns an error, we risk looping forever here
|
||||
// so check that we get a different error than the last time
|
||||
if ( err == errLast )
|
||||
{
|
||||
wxLogError(wxT("OpenGL error state couldn't be reset."));
|
||||
return;
|
||||
}
|
||||
|
||||
errLast = err;
|
||||
|
||||
wxLogError(wxT("OpenGL error %d"), err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EDA_3D_CANVAS implementation
|
||||
*/
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_CANVAS, wxGLCanvas )
|
||||
EVT_PAINT( EDA_3D_CANVAS::OnPaint )
|
||||
|
||||
// key event:
|
||||
EVT_CHAR( EDA_3D_CANVAS::OnChar )
|
||||
|
||||
// mouse events
|
||||
EVT_RIGHT_DOWN( EDA_3D_CANVAS::OnRightClick )
|
||||
EVT_MOUSEWHEEL( EDA_3D_CANVAS::OnMouseWheel )
|
||||
EVT_MOTION( EDA_3D_CANVAS::OnMouseMove )
|
||||
|
||||
// other events
|
||||
EVT_ERASE_BACKGROUND( EDA_3D_CANVAS::OnEraseBackground )
|
||||
EVT_MENU_RANGE( ID_POPUP_3D_VIEW_START, ID_POPUP_3D_VIEW_END, EDA_3D_CANVAS::OnPopUpMenu )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
|
||||
wxGLCanvas( parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE )
|
||||
{
|
||||
m_init = false;
|
||||
m_gllist = 0;
|
||||
// Explicitly create a new rendering context instance for this canvas.
|
||||
m_glRC = new wxGLContext( this );
|
||||
|
||||
DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_CANVAS::~EDA_3D_CANVAS()
|
||||
{
|
||||
ClearLists();
|
||||
m_init = false;
|
||||
delete m_glRC;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::ClearLists()
|
||||
{
|
||||
if( m_gllist > 0 )
|
||||
glDeleteLists( m_gllist, 1 );
|
||||
|
||||
m_gllist = 0;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnChar( wxKeyEvent& event )
|
||||
{
|
||||
SetView3D( event.GetKeyCode() );
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::SetView3D( int keycode )
|
||||
{
|
||||
int ii;
|
||||
double delta_move = 0.7 * g_Parm_3D_Visu.m_Zoom;
|
||||
|
||||
switch( keycode )
|
||||
{
|
||||
case WXK_LEFT:
|
||||
m_draw3dOffset.x -= delta_move;
|
||||
break;
|
||||
|
||||
case WXK_RIGHT:
|
||||
m_draw3dOffset.x += delta_move;
|
||||
break;
|
||||
|
||||
case WXK_UP:
|
||||
m_draw3dOffset.y += delta_move;
|
||||
break;
|
||||
|
||||
case WXK_DOWN:
|
||||
m_draw3dOffset.y -= delta_move;
|
||||
break;
|
||||
|
||||
case WXK_HOME:
|
||||
g_Parm_3D_Visu.m_Zoom = 1.0;
|
||||
m_draw3dOffset.x = m_draw3dOffset.y = 0;
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case WXK_END:
|
||||
break;
|
||||
|
||||
case WXK_F1:
|
||||
g_Parm_3D_Visu.m_Zoom /= 1.4;
|
||||
if( g_Parm_3D_Visu.m_Zoom <= 0.01 )
|
||||
g_Parm_3D_Visu.m_Zoom = 0.01;
|
||||
break;
|
||||
|
||||
case WXK_F2:
|
||||
g_Parm_3D_Visu.m_Zoom *= 1.4;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
break;
|
||||
|
||||
case '-':
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
m_draw3dOffset.x = m_draw3dOffset.y = 0;
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
g_Parm_3D_Visu.m_ROTZ = -90;
|
||||
g_Parm_3D_Visu.m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
g_Parm_3D_Visu.m_ROTZ = 90;
|
||||
g_Parm_3D_Visu.m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
g_Parm_3D_Visu.m_ROTX = -90;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
g_Parm_3D_Visu.m_ROTX = -90;
|
||||
g_Parm_3D_Visu.m_ROTZ = -180;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
g_Parm_3D_Visu.m_ROTX = -180;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event )
|
||||
{
|
||||
if( event.ShiftDown() )
|
||||
{
|
||||
if( event.GetWheelRotation() < 0 )
|
||||
{
|
||||
/* up */
|
||||
SetView3D( WXK_UP );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* down */
|
||||
SetView3D( WXK_DOWN );
|
||||
}
|
||||
}
|
||||
else if( event.ControlDown() )
|
||||
{
|
||||
if( event.GetWheelRotation() > 0 )
|
||||
{
|
||||
/* right */
|
||||
SetView3D( WXK_RIGHT );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* left */
|
||||
SetView3D( WXK_LEFT );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( event.GetWheelRotation() > 0 )
|
||||
{
|
||||
g_Parm_3D_Visu.m_Zoom /= 1.4;
|
||||
|
||||
if( g_Parm_3D_Visu.m_Zoom <= 0.01 )
|
||||
g_Parm_3D_Visu.m_Zoom = 0.01;
|
||||
}
|
||||
else
|
||||
g_Parm_3D_Visu.m_Zoom *= 1.4;
|
||||
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
g_Parm_3D_Visu.m_Beginx = event.GetX();
|
||||
g_Parm_3D_Visu.m_Beginy = event.GetY();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
wxSize size( GetClientSize() );
|
||||
double spin_quat[4];
|
||||
|
||||
if( event.Dragging() )
|
||||
{
|
||||
if( event.LeftIsDown() )
|
||||
{
|
||||
/* drag in progress, simulate trackball */
|
||||
trackball( spin_quat,
|
||||
(2.0 * g_Parm_3D_Visu.m_Beginx - size.x) / size.x,
|
||||
(size.y - 2.0 * g_Parm_3D_Visu.m_Beginy) / size.y,
|
||||
( 2.0 * event.GetX() - size.x) / size.x,
|
||||
( size.y - 2.0 * event.GetY() ) / size.y );
|
||||
|
||||
add_quats( spin_quat, g_Parm_3D_Visu.m_Quat, g_Parm_3D_Visu.m_Quat );
|
||||
}
|
||||
else if( event.MiddleIsDown() )
|
||||
{
|
||||
/* middle button drag -> pan */
|
||||
|
||||
/* Current zoom and an additional factor are taken into account
|
||||
* for the amount of panning. */
|
||||
const double PAN_FACTOR = 8.0 * g_Parm_3D_Visu.m_Zoom;
|
||||
m_draw3dOffset.x -= PAN_FACTOR *
|
||||
( g_Parm_3D_Visu.m_Beginx - event.GetX() ) / size.x;
|
||||
m_draw3dOffset.y -= PAN_FACTOR *
|
||||
(event.GetY() - g_Parm_3D_Visu.m_Beginy) / size.y;
|
||||
}
|
||||
|
||||
/* orientation has changed, redraw mesh */
|
||||
DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
g_Parm_3D_Visu.m_Beginx = event.GetX();
|
||||
g_Parm_3D_Visu.m_Beginy = event.GetY();
|
||||
}
|
||||
|
||||
|
||||
/* Construct and display a popup menu when the right button is clicked.
|
||||
*/
|
||||
void EDA_3D_CANVAS::OnRightClick( wxMouseEvent& event )
|
||||
{
|
||||
wxPoint pos;
|
||||
wxMenu PopUpMenu;
|
||||
|
||||
pos.x = event.GetX();
|
||||
pos.y = event.GetY();
|
||||
|
||||
wxMenuItem* item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMIN, _( "Zoom +" ) );
|
||||
item->SetBitmap( KiBitmap( zoom_in_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_ZOOMOUT, _( "Zoom -" ) );
|
||||
item->SetBitmap( KiBitmap( zoom_out_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZPOS, _( "Top View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_top_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_ZNEG, _( "Bottom View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_bottom_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XPOS, _( "Right View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_right_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_XNEG, _( "Left View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_left_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YPOS, _( "Front View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_front_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_VIEW_YNEG, _( "Back View" ) );
|
||||
item->SetBitmap( KiBitmap( axis3d_back_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopUpMenu.AppendSeparator();
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_LEFT, _( "Move left <-" ) );
|
||||
item->SetBitmap( KiBitmap( left_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_RIGHT, _( "Move right ->" ) );
|
||||
item->SetBitmap( KiBitmap( right_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_UP, _( "Move Up ^" ) );
|
||||
item->SetBitmap( KiBitmap( up_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
item = new wxMenuItem( &PopUpMenu, ID_POPUP_MOVE3D_DOWN, _( "Move Down" ) );
|
||||
item->SetBitmap( KiBitmap( down_xpm ));
|
||||
PopUpMenu.Append( item );
|
||||
|
||||
PopupMenu( &PopUpMenu, pos );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnPopUpMenu( wxCommandEvent& event )
|
||||
{
|
||||
int key = 0;
|
||||
|
||||
switch( event.GetId() )
|
||||
{
|
||||
case ID_POPUP_ZOOMIN:
|
||||
key = WXK_F1;
|
||||
break;
|
||||
|
||||
case ID_POPUP_ZOOMOUT:
|
||||
key = WXK_F2;
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_XPOS:
|
||||
key = 'x';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_XNEG:
|
||||
key = 'X';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_YPOS:
|
||||
key = 'y';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_YNEG:
|
||||
key = 'Y';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_ZPOS:
|
||||
key = 'z';
|
||||
break;
|
||||
|
||||
case ID_POPUP_VIEW_ZNEG:
|
||||
key = 'Z';
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_LEFT:
|
||||
key = WXK_LEFT;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_RIGHT:
|
||||
key = WXK_RIGHT;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_UP:
|
||||
key = WXK_UP;
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE3D_DOWN:
|
||||
key = WXK_DOWN;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
SetView3D( key );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::DisplayStatus()
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( wxT( "dx %3.2f" ), m_draw3dOffset.x );
|
||||
Parent()->SetStatusText( msg, 1 );
|
||||
|
||||
msg.Printf( wxT( "dy %3.2f" ), m_draw3dOffset.y );
|
||||
Parent()->SetStatusText( msg, 2 );
|
||||
|
||||
msg.Printf( wxT( "View: %3.1f" ), 45 * g_Parm_3D_Visu.m_Zoom );
|
||||
Parent()->SetStatusText( msg, 3 );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnPaint( wxPaintEvent& event )
|
||||
{
|
||||
wxPaintDC dc( this );
|
||||
|
||||
Redraw();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnEraseBackground( wxEraseEvent& event )
|
||||
{
|
||||
// Do nothing, to avoid flashing.
|
||||
}
|
||||
|
||||
|
||||
/* Initialize broad parameters for OpenGL */
|
||||
void EDA_3D_CANVAS::InitGL()
|
||||
{
|
||||
wxSize size = GetClientSize();
|
||||
|
||||
if( !m_init )
|
||||
{
|
||||
m_init = true;
|
||||
g_Parm_3D_Visu.m_Zoom = 1.0;
|
||||
m_ZBottom = 1.0;
|
||||
m_ZTop = 10.0;
|
||||
|
||||
glDisable( GL_CULL_FACE ); // show back faces
|
||||
glEnable( GL_DEPTH_TEST ); // Enable z-buferring
|
||||
glEnable( GL_ALPHA_TEST );
|
||||
glEnable( GL_LINE_SMOOTH );
|
||||
// glEnable(GL_POLYGON_SMOOTH); // creates issues with some graphic cards
|
||||
glShadeModel( GL_SMOOTH );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
|
||||
// speedups
|
||||
glEnable( GL_DITHER );
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE );
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
// Initialize alpha blending function.
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
}
|
||||
|
||||
// set viewing projection
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
|
||||
#define MAX_VIEW_ANGLE 160.0 / 45.0
|
||||
if( g_Parm_3D_Visu.m_Zoom > MAX_VIEW_ANGLE )
|
||||
g_Parm_3D_Visu.m_Zoom = MAX_VIEW_ANGLE;
|
||||
|
||||
if( Parent()->ModeIsOrtho() )
|
||||
{
|
||||
// OrthoReductionFactor is chosen so as to provide roughly the same size as
|
||||
// Perspective View
|
||||
const double orthoReductionFactor = 400 / g_Parm_3D_Visu.m_Zoom;
|
||||
|
||||
// Initialize Projection Matrix for Ortographic View
|
||||
glOrtho( -size.x / orthoReductionFactor, size.x / orthoReductionFactor,
|
||||
-size.y / orthoReductionFactor, size.y / orthoReductionFactor, 1, 10 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ratio width / height of the window display
|
||||
double ratio_HV = (double) size.x / size.y;
|
||||
|
||||
// Initialize Projection Matrix for Perspective View
|
||||
gluPerspective( 45.0 * g_Parm_3D_Visu.m_Zoom, ratio_HV, 1, 10 );
|
||||
}
|
||||
|
||||
|
||||
// position viewer
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glTranslatef( 0.0F, 0.0F, -( m_ZBottom + m_ZTop) / 2 );
|
||||
|
||||
// clear color and depth buffers
|
||||
glClearColor( g_Parm_3D_Visu.m_BgColor.m_Red,
|
||||
g_Parm_3D_Visu.m_BgColor.m_Green,
|
||||
g_Parm_3D_Visu.m_BgColor.m_Blue, 1 );
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// Setup light sources:
|
||||
SetLights();
|
||||
|
||||
CheckGLError();
|
||||
}
|
||||
|
||||
|
||||
/* Initialize OpenGL light sources. */
|
||||
void EDA_3D_CANVAS::SetLights()
|
||||
{
|
||||
double light;
|
||||
GLfloat light_color[4];
|
||||
|
||||
/* set viewing projection */
|
||||
light_color[3] = 1.0;
|
||||
GLfloat Z_axis_pos[4] = { 0.0, 0.0, 3.0, 0.0 };
|
||||
GLfloat lowZ_axis_pos[4] = { 0.0, 0.0, -3.0, 0.5 };
|
||||
|
||||
/* activate light */
|
||||
light = 1.0;
|
||||
light_color[0] = light_color[1] = light_color[2] = light;
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, Z_axis_pos );
|
||||
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_color );
|
||||
light = 0.3;
|
||||
light_color[0] = light_color[1] = light_color[2] = light;
|
||||
glLightfv( GL_LIGHT1, GL_POSITION, lowZ_axis_pos );
|
||||
glLightfv( GL_LIGHT1, GL_DIFFUSE, light_color );
|
||||
glEnable( GL_LIGHT0 ); // White spot on Z axis
|
||||
glEnable( GL_LIGHT1 ); // White spot on Z axis ( bottom)
|
||||
glEnable( GL_LIGHTING );
|
||||
}
|
||||
|
||||
|
||||
/* Create a Screenshot of the current 3D view.
|
||||
* Output file format is png or jpeg, or image is copied to the clipboard
|
||||
*/
|
||||
void EDA_3D_CANVAS::TakeScreenshot( wxCommandEvent& event )
|
||||
{
|
||||
wxFileName fn( Parent()->GetDefaultFileName() );
|
||||
wxString FullFileName;
|
||||
wxString file_ext, mask;
|
||||
bool fmt_is_jpeg = false;
|
||||
|
||||
if( event.GetId() == ID_MENU_SCREENCOPY_JPEG )
|
||||
fmt_is_jpeg = true;
|
||||
|
||||
if( event.GetId() != ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
file_ext = fmt_is_jpeg ? wxT( "jpg" ) : wxT( "png" );
|
||||
mask = wxT( "*." ) + file_ext;
|
||||
FullFileName = Parent()->GetDefaultFileName();
|
||||
fn.SetExt( file_ext );
|
||||
|
||||
FullFileName = EDA_FileSelector( _( "3D Image filename:" ), wxEmptyString,
|
||||
fn.GetFullName(), file_ext, mask, this,
|
||||
wxFD_SAVE, true );
|
||||
|
||||
if( FullFileName.IsEmpty() )
|
||||
return;
|
||||
|
||||
// Be sure the screen area destroyed by the file dialog is redrawn before making
|
||||
// a screen copy.
|
||||
// Without this call, under Linux the screen refresh is made to late.
|
||||
wxYield();
|
||||
}
|
||||
|
||||
struct vieport_params
|
||||
{
|
||||
GLint originx;
|
||||
GLint originy;
|
||||
GLint x;
|
||||
GLint y;
|
||||
} viewport;
|
||||
|
||||
// Build image from the 3D buffer
|
||||
wxWindowUpdateLocker noUpdates( this );
|
||||
glGetIntegerv( GL_VIEWPORT, (GLint*) &viewport );
|
||||
|
||||
unsigned char* pixelbuffer = (unsigned char*) malloc( viewport.x * viewport.y * 3 );
|
||||
unsigned char* alphabuffer = (unsigned char*) malloc( viewport.x * viewport.y );
|
||||
wxImage image( viewport.x, viewport.y );
|
||||
|
||||
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
|
||||
glReadBuffer( GL_BACK_LEFT );
|
||||
glReadPixels( viewport.originx, viewport.originy,
|
||||
viewport.x, viewport.y,
|
||||
GL_RGB, GL_UNSIGNED_BYTE, pixelbuffer );
|
||||
glReadPixels( viewport.originx, viewport.originy,
|
||||
viewport.x, viewport.y,
|
||||
GL_ALPHA, GL_UNSIGNED_BYTE, alphabuffer );
|
||||
|
||||
|
||||
image.SetData( pixelbuffer );
|
||||
image.SetAlpha( alphabuffer );
|
||||
image = image.Mirror( false );
|
||||
wxBitmap bitmap( image );
|
||||
|
||||
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
wxBitmapDataObject* dobjBmp = new wxBitmapDataObject;
|
||||
dobjBmp->SetBitmap( bitmap );
|
||||
|
||||
if( wxTheClipboard->Open() )
|
||||
{
|
||||
if( !wxTheClipboard->SetData( dobjBmp ) )
|
||||
wxMessageBox( _( "Failed to copy image to clipboard" ) );
|
||||
|
||||
wxTheClipboard->Flush(); /* the data in clipboard will stay
|
||||
* available after the
|
||||
* application exits */
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
|
||||
if( !image.SaveFile( FullFileName,
|
||||
fmt_is_jpeg ? wxBITMAP_TYPE_JPEG : wxBITMAP_TYPE_PNG ) )
|
||||
wxMessageBox( _( "Can't save file" ) );
|
||||
|
||||
image.Destroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_viewer.h
|
||||
*/
|
||||
|
||||
#ifndef _3D_CANVAS_H_
|
||||
#define _3D_CANVAS_H_
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include <3d_struct.h>
|
||||
|
||||
class BOARD_DESIGN_SETTINGS;
|
||||
class EDA_3D_FRAME;
|
||||
class S3D_VERTEX;
|
||||
class SEGVIA;
|
||||
class D_PAD;
|
||||
|
||||
|
||||
class EDA_3D_CANVAS : public wxGLCanvas
|
||||
{
|
||||
private:
|
||||
bool m_init;
|
||||
GLuint m_gllist;
|
||||
wxGLContext* m_glRC;
|
||||
wxRealPoint m_draw3dOffset; // offset to draw the 3 mesh.
|
||||
double m_ZBottom; // position of the back layer
|
||||
double m_ZTop; // position of the front layer
|
||||
|
||||
public:
|
||||
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
|
||||
~EDA_3D_CANVAS();
|
||||
|
||||
EDA_3D_FRAME* Parent() { return (EDA_3D_FRAME*)GetParent(); }
|
||||
|
||||
void ClearLists();
|
||||
|
||||
// Event functions:
|
||||
void OnPaint( wxPaintEvent& event );
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
void OnChar( wxKeyEvent& event );
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
void OnRightClick( wxMouseEvent& event );
|
||||
void OnPopUpMenu( wxCommandEvent& event );
|
||||
void TakeScreenshot( wxCommandEvent& event );
|
||||
void OnEnterWindow( wxMouseEvent& event );
|
||||
|
||||
// Display functions
|
||||
GLuint DisplayCubeforTest(); // Just a test function
|
||||
void SetView3D( int keycode );
|
||||
void DisplayStatus();
|
||||
void Redraw( bool finish = false );
|
||||
void Render();
|
||||
|
||||
/**
|
||||
* Function CreateDrawGL_List
|
||||
* Prepares the parameters of the OpenGL draw list
|
||||
* creates the OpenGL draw list items (board, grid ...
|
||||
*/
|
||||
GLuint CreateDrawGL_List();
|
||||
void InitGL();
|
||||
void SetLights();
|
||||
void SetOffset(double aPosX, double aPosY)
|
||||
{
|
||||
m_draw3dOffset.x = aPosX;
|
||||
m_draw3dOffset.y = aPosY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function BuildBoard3DView
|
||||
* Called by CreateDrawGL_List()
|
||||
* Fills the OpenGL draw list with board items draw list.
|
||||
*/
|
||||
void BuildBoard3DView();
|
||||
|
||||
void DrawGrid( double aGriSizeMM );
|
||||
void Draw3DViaHole( SEGVIA * aVia );
|
||||
void Draw3DPadHole( D_PAD * aPad );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif /* _3D_CANVAS_H_ */
|
||||
@@ -1,758 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2022 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "../3d_rendering/camera.h"
|
||||
#include "board_adapter.h"
|
||||
#include <board_design_settings.h>
|
||||
#include <board_stackup_manager/board_stackup.h>
|
||||
#include <board_stackup_manager/stackup_predefined_prms.h>
|
||||
#include <3d_rendering/raytracing/shapes2D/polygon_2d.h>
|
||||
#include <board.h>
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
#include <3d_math.h>
|
||||
#include "3d_fastmath.h"
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <pgm_base.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <wx/log.h>
|
||||
#include <pcbnew_settings.h>
|
||||
#include <advanced_config.h>
|
||||
|
||||
|
||||
#define DEFAULT_BOARD_THICKNESS pcbIUScale.mmToIU( 1.6 )
|
||||
#define DEFAULT_COPPER_THICKNESS pcbIUScale.mmToIU( 0.035 ) // for 35 um
|
||||
// The solder mask layer (and silkscreen) thickness
|
||||
#define DEFAULT_TECH_LAYER_THICKNESS pcbIUScale.mmToIU( 0.025 )
|
||||
// The solder paste thickness is chosen bigger than the solder mask layer
|
||||
// to be sure is covers the mask when overlapping.
|
||||
#define SOLDERPASTE_LAYER_THICKNESS pcbIUScale.mmToIU( 0.04 )
|
||||
|
||||
|
||||
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_SilkscreenColors;
|
||||
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_MaskColors;
|
||||
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_PasteColors;
|
||||
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_FinishColors;
|
||||
CUSTOM_COLORS_LIST BOARD_ADAPTER::g_BoardColors;
|
||||
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundTop;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBackgroundBot;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSilkscreen;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderMask;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSolderPaste;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultSurfaceFinish;
|
||||
KIGFX::COLOR4D BOARD_ADAPTER::g_DefaultBoardBody;
|
||||
|
||||
// To be used in Raytracing render to create bevels on layer items
|
||||
float g_BevelThickness3DU = 0.0f;
|
||||
|
||||
static bool g_ColorsLoaded = false;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar *BOARD_ADAPTER::m_logTrace = wxT( "KI_TRACE_EDA_CINFO3D_VISU" );
|
||||
|
||||
|
||||
BOARD_ADAPTER::BOARD_ADAPTER() :
|
||||
m_Cfg( nullptr ),
|
||||
m_IsBoardView( true ),
|
||||
m_MousewheelPanning( true ),
|
||||
m_IsPreviewer( false ),
|
||||
m_board( nullptr ),
|
||||
m_3dModelManager( nullptr ),
|
||||
m_renderSettings( nullptr ),
|
||||
m_colors( nullptr ),
|
||||
m_layerZcoordTop(),
|
||||
m_layerZcoordBottom()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::BOARD_ADAPTER" ) );
|
||||
|
||||
ReloadColorSettings();
|
||||
|
||||
m_boardPos = VECTOR2I();
|
||||
m_boardSize = VECTOR2I();
|
||||
m_boardCenter = SFVEC3F( 0.0f );
|
||||
|
||||
m_boardBoundingBox.Reset();
|
||||
|
||||
m_throughHoleIds.Clear();
|
||||
m_throughHoleOds.Clear();
|
||||
m_throughHoleAnnularRings.Clear();
|
||||
|
||||
m_copperLayersCount = 2;
|
||||
|
||||
m_biuTo3Dunits = 1.0;
|
||||
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
|
||||
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
||||
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
||||
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
|
||||
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
|
||||
|
||||
m_trackCount = 0;
|
||||
m_viaCount = 0;
|
||||
m_averageViaHoleDiameter = 0.0f;
|
||||
m_holeCount = 0;
|
||||
m_averageHoleDiameter = 0.0f;
|
||||
m_averageTrackWidth = 0.0f;
|
||||
|
||||
m_BgColorBot = SFVEC4F( 0.4, 0.4, 0.5, 1.0 );
|
||||
m_BgColorTop = SFVEC4F( 0.8, 0.8, 0.9, 1.0 );
|
||||
m_BoardBodyColor = SFVEC4F( 0.4, 0.4, 0.5, 0.9 );
|
||||
m_SolderMaskColorTop = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
|
||||
m_SolderMaskColorBot = SFVEC4F( 0.1, 0.2, 0.1, 0.83 );
|
||||
m_SolderPasteColor = SFVEC4F( 0.4, 0.4, 0.4, 1.0 );
|
||||
m_SilkScreenColorTop = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
|
||||
m_SilkScreenColorBot = SFVEC4F( 0.9, 0.9, 0.9, 1.0 );
|
||||
m_CopperColor = SFVEC4F( 0.75, 0.61, 0.23, 1.0 );
|
||||
|
||||
m_platedPadsFront = nullptr;
|
||||
m_platedPadsBack = nullptr;
|
||||
|
||||
m_frontPlatedPadPolys = nullptr;
|
||||
m_backPlatedPadPolys = nullptr;
|
||||
|
||||
if( !g_ColorsLoaded )
|
||||
{
|
||||
#define ADD_COLOR( list, r, g, b, a, name ) \
|
||||
list.emplace_back( r/255.0, g/255.0, b/255.0, a, name )
|
||||
|
||||
ADD_COLOR( g_SilkscreenColors, 245, 245, 245, 1.0, NotSpecifiedPrm() ); // White
|
||||
ADD_COLOR( g_SilkscreenColors, 20, 51, 36, 1.0, wxT( "Green" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 181, 19, 21, 1.0, wxT( "Red" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 2, 59, 162, 1.0, wxT( "Blue" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 11, 11, 11, 1.0, wxT( "Black" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 245, 245, 245, 1.0, wxT( "White" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 32, 2, 53, 1.0, wxT( "Purple" ) );
|
||||
ADD_COLOR( g_SilkscreenColors, 194, 195, 0, 1.0, wxT( "Yellow" ) );
|
||||
|
||||
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, NotSpecifiedPrm() ); // Green
|
||||
ADD_COLOR( g_MaskColors, 20, 51, 36, 0.83, wxT( "Green" ) );
|
||||
ADD_COLOR( g_MaskColors, 91, 168, 12, 0.83, wxT( "Light Green" ) );
|
||||
ADD_COLOR( g_MaskColors, 13, 104, 11, 0.83, wxT( "Saturated Green" ) );
|
||||
ADD_COLOR( g_MaskColors, 181, 19, 21, 0.83, wxT( "Red" ) );
|
||||
ADD_COLOR( g_MaskColors, 210, 40, 14, 0.83, wxT( "Light Red" ) );
|
||||
ADD_COLOR( g_MaskColors, 239, 53, 41, 0.83, wxT( "Red/Orange" ) );
|
||||
ADD_COLOR( g_MaskColors, 2, 59, 162, 0.83, wxT( "Blue" ) );
|
||||
ADD_COLOR( g_MaskColors, 54, 79, 116, 0.83, wxT( "Light Blue 1" ) );
|
||||
ADD_COLOR( g_MaskColors, 61, 85, 130, 0.83, wxT( "Light Blue 2" ) );
|
||||
ADD_COLOR( g_MaskColors, 21, 70, 80, 0.83, wxT( "Green/Blue" ) );
|
||||
ADD_COLOR( g_MaskColors, 11, 11, 11, 0.83, wxT( "Black" ) );
|
||||
ADD_COLOR( g_MaskColors, 245, 245, 245, 0.83, wxT( "White" ) );
|
||||
ADD_COLOR( g_MaskColors, 32, 2, 53, 0.83, wxT( "Purple" ) );
|
||||
ADD_COLOR( g_MaskColors, 119, 31, 91, 0.83, wxT( "Light Purple" ) );
|
||||
ADD_COLOR( g_MaskColors, 194, 195, 0, 0.83, wxT( "Yellow" ) );
|
||||
|
||||
ADD_COLOR( g_PasteColors, 128, 128, 128, 1.0, wxT( "Grey" ) );
|
||||
ADD_COLOR( g_PasteColors, 90, 90, 90, 1.0, wxT( "Dark Grey" ) );
|
||||
ADD_COLOR( g_PasteColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
|
||||
|
||||
ADD_COLOR( g_FinishColors, 184, 115, 50, 1.0, wxT( "Copper" ) );
|
||||
ADD_COLOR( g_FinishColors, 178, 156, 0, 1.0, wxT( "Gold" ) );
|
||||
ADD_COLOR( g_FinishColors, 213, 213, 213, 1.0, wxT( "Silver" ) );
|
||||
ADD_COLOR( g_FinishColors, 160, 160, 160, 1.0, wxT( "Tin" ) );
|
||||
|
||||
ADD_COLOR( g_BoardColors, 51, 43, 22, 0.83, wxT( "FR4 natural, dark" ) );
|
||||
ADD_COLOR( g_BoardColors, 109, 116, 75, 0.83, wxT( "FR4 natural" ) );
|
||||
ADD_COLOR( g_BoardColors, 252, 252, 250, 0.90, wxT( "PTFE natural" ) );
|
||||
ADD_COLOR( g_BoardColors, 205, 130, 0, 0.68, wxT( "Polyimide" ) );
|
||||
ADD_COLOR( g_BoardColors, 92, 17, 6, 0.90, wxT( "Phenolic natural" ) );
|
||||
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 1" ) );
|
||||
ADD_COLOR( g_BoardColors, 160, 123, 54, 0.83, wxT( "Brown 2" ) );
|
||||
ADD_COLOR( g_BoardColors, 146, 99, 47, 0.83, wxT( "Brown 3" ) );
|
||||
ADD_COLOR( g_BoardColors, 213, 213, 213, 1.0, wxT( "Aluminum" ) );
|
||||
|
||||
g_DefaultBackgroundTop = COLOR4D( 0.80, 0.80, 0.90, 1.0 );
|
||||
g_DefaultBackgroundBot = COLOR4D( 0.40, 0.40, 0.50, 1.0 );
|
||||
|
||||
g_DefaultSilkscreen = COLOR4D( 0.94, 0.94, 0.94, 1.0 );
|
||||
g_DefaultSolderMask = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
|
||||
g_DefaultSolderPaste = COLOR4D( 0.50, 0.50, 0.50, 1.0 );
|
||||
g_DefaultSurfaceFinish = COLOR4D( 0.75, 0.61, 0.23, 1.0 );
|
||||
g_DefaultBoardBody = COLOR4D( 0.43, 0.45, 0.30, 0.90 );
|
||||
|
||||
g_ColorsLoaded = true;
|
||||
}
|
||||
#undef ADD_COLOR
|
||||
}
|
||||
|
||||
|
||||
BOARD_ADAPTER::~BOARD_ADAPTER()
|
||||
{
|
||||
destroyLayers();
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::ReloadColorSettings() noexcept
|
||||
{
|
||||
wxASSERT( PgmOrNull() );
|
||||
|
||||
PCBNEW_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
|
||||
m_colors = Pgm().GetSettingsManager().GetColorSettings( settings->m_ColorTheme );
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_ADAPTER::Is3dLayerEnabled( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
|
||||
|
||||
if( m_board && !m_board->IsLayerEnabled( aLayer ) )
|
||||
return false;
|
||||
|
||||
// see if layer needs to be shown
|
||||
// check the flags
|
||||
switch( aLayer )
|
||||
{
|
||||
case B_Adhes:
|
||||
case F_Adhes:
|
||||
return m_Cfg->m_Render.show_adhesive;
|
||||
|
||||
case B_Paste:
|
||||
case F_Paste:
|
||||
return m_Cfg->m_Render.show_solderpaste;
|
||||
|
||||
case B_SilkS:
|
||||
case F_SilkS:
|
||||
return m_Cfg->m_Render.show_silkscreen;
|
||||
|
||||
case B_Mask:
|
||||
case F_Mask:
|
||||
return m_Cfg->m_Render.show_soldermask;
|
||||
|
||||
case Dwgs_User:
|
||||
case Cmts_User:
|
||||
return !m_Cfg->m_Render.realistic && m_Cfg->m_Render.show_comments;
|
||||
|
||||
case Eco1_User:
|
||||
case Eco2_User:
|
||||
return !m_Cfg->m_Render.realistic && m_Cfg->m_Render.show_eco;
|
||||
|
||||
case Edge_Cuts:
|
||||
return !m_Cfg->m_Render.realistic && !m_Cfg->m_Render.show_board_body;
|
||||
|
||||
case Margin:
|
||||
return !m_Cfg->m_Render.realistic;
|
||||
|
||||
case B_Cu:
|
||||
case F_Cu:
|
||||
return !m_board || m_board->IsLayerVisible( aLayer ) || m_Cfg->m_Render.realistic
|
||||
|| m_board->IsFootprintHolder();
|
||||
|
||||
default:
|
||||
// the layer is an internal copper layer, used the visibility
|
||||
return m_board && m_board->IsLayerVisible( aLayer );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_ADAPTER::IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const
|
||||
{
|
||||
if( m_IsPreviewer ) // In panel Preview, footprints are always shown, of course
|
||||
return true;
|
||||
|
||||
if( aFPAttributes & FP_EXCLUDE_FROM_POS_FILES )
|
||||
{
|
||||
if( !m_Cfg->m_Render.show_footprints_not_in_posfile )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aFPAttributes & FP_SMD )
|
||||
return m_Cfg->m_Render.show_footprints_insert;
|
||||
|
||||
if( aFPAttributes & FP_THROUGH_HOLE )
|
||||
return m_Cfg->m_Render.show_footprints_normal;
|
||||
|
||||
return m_Cfg->m_Render.show_footprints_virtual;
|
||||
}
|
||||
|
||||
|
||||
int BOARD_ADAPTER::GetHolePlatingThickness() const noexcept
|
||||
{
|
||||
return m_board ? m_board->GetDesignSettings().GetHolePlatingThickness()
|
||||
: DEFAULT_COPPER_THICKNESS;
|
||||
}
|
||||
|
||||
|
||||
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( float aDiameter3DU ) const
|
||||
{
|
||||
wxASSERT( aDiameter3DU > 0.0f );
|
||||
|
||||
return GetCircleSegmentCount( (int)( aDiameter3DU / m_biuTo3Dunits ) );
|
||||
}
|
||||
|
||||
|
||||
unsigned int BOARD_ADAPTER::GetCircleSegmentCount( int aDiameterBIU ) const
|
||||
{
|
||||
wxASSERT( aDiameterBIU > 0 );
|
||||
|
||||
return GetArcToSegmentCount( aDiameterBIU / 2, ARC_HIGH_DEF, FULL_CIRCLE );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::InitSettings" ) );
|
||||
|
||||
if( aStatusReporter )
|
||||
aStatusReporter->Report( _( "Build board outline" ) );
|
||||
|
||||
wxString msg;
|
||||
|
||||
const bool haveOutline = createBoardPolygon( &msg );
|
||||
|
||||
if( aWarningReporter )
|
||||
{
|
||||
if( !haveOutline )
|
||||
aWarningReporter->Report( msg, RPT_SEVERITY_WARNING );
|
||||
else
|
||||
aWarningReporter->Report( wxEmptyString );
|
||||
}
|
||||
|
||||
BOX2I bbbox;
|
||||
|
||||
if( m_board )
|
||||
{
|
||||
bbbox = m_board->ComputeBoundingBox( !m_board->IsFootprintHolder()
|
||||
&& m_Cfg->m_Render.realistic
|
||||
&& haveOutline );
|
||||
}
|
||||
|
||||
// Gives a non null size to avoid issues in zoom / scale calculations
|
||||
if( ( bbbox.GetWidth() == 0 ) && ( bbbox.GetHeight() == 0 ) )
|
||||
bbbox.Inflate( pcbIUScale.mmToIU( 10 ) );
|
||||
|
||||
m_boardSize = bbbox.GetSize();
|
||||
m_boardPos = bbbox.Centre();
|
||||
|
||||
wxASSERT( (m_boardSize.x > 0) && (m_boardSize.y > 0) );
|
||||
|
||||
m_boardPos.y = -m_boardPos.y; // The y coord is inverted in 3D viewer
|
||||
|
||||
m_copperLayersCount = m_board ? m_board->GetCopperLayerCount() : 2;
|
||||
|
||||
// Ensure the board has 2 sides for 3D views, because it is hard to find
|
||||
// a *really* single side board in the true life...
|
||||
if( m_copperLayersCount < 2 )
|
||||
m_copperLayersCount = 2;
|
||||
|
||||
// Calculate the conversion to apply to all positions.
|
||||
m_biuTo3Dunits = RANGE_SCALE_3D / std::max( m_boardSize.x, m_boardSize.y );
|
||||
|
||||
m_boardBodyThickness3DU = DEFAULT_BOARD_THICKNESS * m_biuTo3Dunits;
|
||||
m_frontCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
||||
m_backCopperThickness3DU = DEFAULT_COPPER_THICKNESS * m_biuTo3Dunits;
|
||||
m_nonCopperLayerThickness3DU = DEFAULT_TECH_LAYER_THICKNESS * m_biuTo3Dunits;
|
||||
m_solderPasteLayerThickness3DU = SOLDERPASTE_LAYER_THICKNESS * m_biuTo3Dunits;
|
||||
|
||||
g_BevelThickness3DU = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_3DRT_BevelHeight_um / 1000.0 ) * m_biuTo3Dunits;
|
||||
|
||||
if( m_board )
|
||||
{
|
||||
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
if( bds.GetStackupDescriptor().GetCount() )
|
||||
{
|
||||
int thickness = 0;
|
||||
|
||||
for( BOARD_STACKUP_ITEM* item : bds.GetStackupDescriptor().GetList() )
|
||||
{
|
||||
switch( item->GetType() )
|
||||
{
|
||||
case BS_ITEM_TYPE_DIELECTRIC:
|
||||
for( int sublayer = 0; sublayer < item->GetSublayersCount(); sublayer++ )
|
||||
thickness += item->GetThickness( sublayer );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_COPPER:
|
||||
if( item->GetBrdLayerId() == F_Cu )
|
||||
m_frontCopperThickness3DU = item->GetThickness() * m_biuTo3Dunits;
|
||||
else if( item->GetBrdLayerId() == B_Cu )
|
||||
m_backCopperThickness3DU = item->GetThickness() * m_biuTo3Dunits;
|
||||
else if( item->IsEnabled() )
|
||||
thickness += item->GetThickness();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_boardBodyThickness3DU = thickness * m_biuTo3Dunits;
|
||||
}
|
||||
}
|
||||
|
||||
// Init Z position of each layer
|
||||
// calculate z position for each copper layer
|
||||
// Zstart = -m_epoxyThickness / 2.0 is the z position of the back (bottom layer) (layer id = 31)
|
||||
// Zstart = +m_epoxyThickness / 2.0 is the z position of the front (top layer) (layer id = 0)
|
||||
|
||||
// ____==__________==________==______ <- Bottom = +m_epoxyThickness / 2.0,
|
||||
// | | Top = Bottom + m_copperThickness
|
||||
// |__________________________________|
|
||||
// == == == == <- Bottom = -m_epoxyThickness / 2.0,
|
||||
// Top = Bottom - m_copperThickness
|
||||
|
||||
unsigned int layer;
|
||||
|
||||
for( layer = 0; layer < m_copperLayersCount; ++layer )
|
||||
{
|
||||
// This approximates internal layer positions (because we're treating all the dielectric
|
||||
// layers as having the same thickness). But we don't render them anyway so it doesn't
|
||||
// really matter.
|
||||
m_layerZcoordBottom[layer] = m_boardBodyThickness3DU / 2.0f -
|
||||
(m_boardBodyThickness3DU * layer / (m_copperLayersCount - 1) );
|
||||
|
||||
if( layer < (m_copperLayersCount / 2) )
|
||||
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] + m_frontCopperThickness3DU;
|
||||
else
|
||||
m_layerZcoordTop[layer] = m_layerZcoordBottom[layer] - m_backCopperThickness3DU;
|
||||
}
|
||||
|
||||
#define layerThicknessMargin 1.1
|
||||
const float zpos_offset = m_nonCopperLayerThickness3DU * layerThicknessMargin;
|
||||
|
||||
// Fill remaining unused copper layers and back layer zpos with -m_boardBodyThickness / 2.0
|
||||
for( ; layer < MAX_CU_LAYERS; layer++ )
|
||||
{
|
||||
m_layerZcoordBottom[layer] = -( m_boardBodyThickness3DU / 2.0f );
|
||||
m_layerZcoordTop[layer] = -( m_boardBodyThickness3DU / 2.0f ) - m_backCopperThickness3DU;
|
||||
}
|
||||
|
||||
// This is the top of the copper layer thickness.
|
||||
const float zpos_copperTop_back = m_layerZcoordTop[B_Cu];
|
||||
const float zpos_copperTop_front = m_layerZcoordTop[F_Cu];
|
||||
|
||||
// calculate z position for each non copper layer
|
||||
// Solder mask and Solder paste have the same Z position
|
||||
for( int layer_id = MAX_CU_LAYERS; layer_id < PCB_LAYER_ID_COUNT; ++layer_id )
|
||||
{
|
||||
float zposTop;
|
||||
float zposBottom;
|
||||
|
||||
switch( layer_id )
|
||||
{
|
||||
case B_Adhes:
|
||||
zposBottom = zpos_copperTop_back - 2.0f * zpos_offset;
|
||||
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case F_Adhes:
|
||||
zposBottom = zpos_copperTop_front + 2.0f * zpos_offset;
|
||||
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case B_Mask:
|
||||
zposBottom = zpos_copperTop_back;
|
||||
zposTop = zpos_copperTop_back - m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case B_Paste:
|
||||
zposBottom = zpos_copperTop_back;
|
||||
zposTop = zpos_copperTop_back - m_solderPasteLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case F_Mask:
|
||||
zposBottom = zpos_copperTop_front;
|
||||
zposTop = zpos_copperTop_front + m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case F_Paste:
|
||||
zposBottom = zpos_copperTop_front;
|
||||
zposTop = zpos_copperTop_front + m_solderPasteLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case B_SilkS:
|
||||
zposBottom = zpos_copperTop_back - 1.0f * zpos_offset;
|
||||
zposTop = zposBottom - m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
case F_SilkS:
|
||||
zposBottom = zpos_copperTop_front + 1.0f * zpos_offset;
|
||||
zposTop = zposBottom + m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
|
||||
// !TODO: review
|
||||
default:
|
||||
zposTop = zpos_copperTop_front + (layer_id - MAX_CU_LAYERS + 3.0f) * zpos_offset;
|
||||
zposBottom = zposTop - m_nonCopperLayerThickness3DU;
|
||||
break;
|
||||
}
|
||||
|
||||
m_layerZcoordTop[layer_id] = zposTop;
|
||||
m_layerZcoordBottom[layer_id] = zposBottom;
|
||||
}
|
||||
|
||||
m_boardCenter = SFVEC3F( m_boardPos.x * m_biuTo3Dunits, m_boardPos.y * m_biuTo3Dunits, 0.0f );
|
||||
|
||||
SFVEC3F boardSize = SFVEC3F( m_boardSize.x * m_biuTo3Dunits, m_boardSize.y * m_biuTo3Dunits,
|
||||
0.0f );
|
||||
boardSize /= 2.0f;
|
||||
|
||||
SFVEC3F boardMin = ( m_boardCenter - boardSize );
|
||||
SFVEC3F boardMax = ( m_boardCenter + boardSize );
|
||||
|
||||
boardMin.z = m_layerZcoordTop[B_Adhes];
|
||||
boardMax.z = m_layerZcoordTop[F_Adhes];
|
||||
|
||||
m_boardBoundingBox = BBOX_3D( boardMin, boardMax );
|
||||
|
||||
#ifdef PRINT_STATISTICS_3D_VIEWER
|
||||
unsigned stats_startCreateBoardPolyTime = GetRunningMicroSecs();
|
||||
#endif
|
||||
|
||||
if( aStatusReporter )
|
||||
aStatusReporter->Report( _( "Create layers" ) );
|
||||
|
||||
createLayers( aStatusReporter );
|
||||
|
||||
COLOR_SETTINGS* colors = Pgm().GetSettingsManager().GetColorSettings();
|
||||
|
||||
auto to_SFVEC4F =
|
||||
[]( const COLOR4D& src )
|
||||
{
|
||||
return SFVEC4F( src.r, src.g, src.b, src.a );
|
||||
};
|
||||
|
||||
m_BgColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_BACKGROUND_TOP ) );
|
||||
m_BgColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_BACKGROUND_BOTTOM ) );
|
||||
|
||||
m_SolderPasteColor = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERPASTE ) );
|
||||
|
||||
if( m_board && colors->GetUseBoardStackupColors() )
|
||||
{
|
||||
const BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
|
||||
|
||||
auto findColor =
|
||||
[]( const wxString& aColorName, const CUSTOM_COLORS_LIST& aColorSet )
|
||||
{
|
||||
if( aColorName.StartsWith( wxT( "#" ) ) )
|
||||
{
|
||||
return KIGFX::COLOR4D( aColorName );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const CUSTOM_COLOR_ITEM& color : aColorSet )
|
||||
{
|
||||
if( color.m_ColorName == aColorName )
|
||||
return color.m_Color;
|
||||
}
|
||||
}
|
||||
|
||||
return KIGFX::COLOR4D();
|
||||
};
|
||||
|
||||
m_SilkScreenColorTop = to_SFVEC4F( g_DefaultSilkscreen );
|
||||
m_SilkScreenColorBot = to_SFVEC4F( g_DefaultSilkscreen );
|
||||
m_SolderMaskColorTop = to_SFVEC4F( g_DefaultSolderMask );
|
||||
m_SolderMaskColorBot = to_SFVEC4F( g_DefaultSolderMask );
|
||||
|
||||
KIGFX::COLOR4D bodyColor( 0, 0, 0, 0 );
|
||||
|
||||
for( const BOARD_STACKUP_ITEM* stackupItem : stackup.GetList() )
|
||||
{
|
||||
wxString colorName = stackupItem->GetColor();
|
||||
|
||||
switch( stackupItem->GetType() )
|
||||
{
|
||||
case BS_ITEM_TYPE_SILKSCREEN:
|
||||
if( stackupItem->GetBrdLayerId() == F_SilkS )
|
||||
m_SilkScreenColorTop = to_SFVEC4F( findColor( colorName, g_SilkscreenColors ) );
|
||||
else
|
||||
m_SilkScreenColorBot = to_SFVEC4F( findColor( colorName, g_SilkscreenColors ) );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_SOLDERMASK:
|
||||
if( stackupItem->GetBrdLayerId() == F_Mask )
|
||||
m_SolderMaskColorTop = to_SFVEC4F( findColor( colorName, g_MaskColors ) );
|
||||
else
|
||||
m_SolderMaskColorBot = to_SFVEC4F( findColor( colorName, g_MaskColors ) );
|
||||
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_DIELECTRIC:
|
||||
{
|
||||
KIGFX::COLOR4D layerColor = findColor( colorName, g_BoardColors );
|
||||
|
||||
if( bodyColor == COLOR4D( 0, 0, 0, 0 ) )
|
||||
bodyColor = layerColor;
|
||||
else
|
||||
bodyColor = bodyColor.Mix( layerColor, 1.0 - layerColor.a );
|
||||
|
||||
bodyColor.a += ( 1.0 - bodyColor.a ) * layerColor.a / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( bodyColor != COLOR4D( 0, 0, 0, 0 ) )
|
||||
m_BoardBodyColor = to_SFVEC4F( bodyColor );
|
||||
else
|
||||
m_BoardBodyColor = to_SFVEC4F( g_DefaultBoardBody );
|
||||
|
||||
const wxString& finishName = stackup.m_FinishType;
|
||||
|
||||
if( finishName.EndsWith( wxT( "OSP" ) ) )
|
||||
{
|
||||
m_CopperColor = to_SFVEC4F( findColor( wxT( "Copper" ), g_FinishColors ) );
|
||||
}
|
||||
else if( finishName.EndsWith( wxT( "IG" ) )
|
||||
|| finishName.EndsWith( wxT( "gold" ) ) )
|
||||
{
|
||||
m_CopperColor = to_SFVEC4F( findColor( wxT( "Gold" ), g_FinishColors ) );
|
||||
}
|
||||
else if( finishName.StartsWith( wxT( "HAL" ) )
|
||||
|| finishName.StartsWith( wxT( "HASL" ) )
|
||||
|| finishName.EndsWith( wxT( "tin" ) )
|
||||
|| finishName.EndsWith( wxT( "nickel" ) ) )
|
||||
{
|
||||
m_CopperColor = to_SFVEC4F( findColor( wxT( "Tin" ), g_FinishColors ) );
|
||||
}
|
||||
else if( finishName.EndsWith( wxT( "silver" ) ) )
|
||||
{
|
||||
m_CopperColor = to_SFVEC4F( findColor( wxT( "Silver" ), g_FinishColors ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CopperColor = to_SFVEC4F( g_DefaultSurfaceFinish );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SilkScreenColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_SILKSCREEN_BOTTOM ) );
|
||||
m_SilkScreenColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_SILKSCREEN_TOP ) );
|
||||
m_SolderMaskColorBot = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERMASK_BOTTOM ) );
|
||||
m_SolderMaskColorTop = to_SFVEC4F( colors->GetColor( LAYER_3D_SOLDERMASK_TOP ) );
|
||||
m_CopperColor = to_SFVEC4F( colors->GetColor( LAYER_3D_COPPER ) );
|
||||
m_BoardBodyColor = to_SFVEC4F( colors->GetColor( LAYER_3D_BOARD ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
|
||||
{
|
||||
m_board_poly.RemoveAllContours();
|
||||
|
||||
if( !m_board )
|
||||
return false;
|
||||
|
||||
bool success;
|
||||
|
||||
if( m_board->IsFootprintHolder() )
|
||||
{
|
||||
if( !m_board->GetFirstFootprint() )
|
||||
{
|
||||
if( aErrorMsg )
|
||||
*aErrorMsg = _( "No footprint loaded." );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// max dist from one endPt to next startPt
|
||||
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
|
||||
|
||||
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
|
||||
m_board->GetDesignSettings().m_MaxError,
|
||||
chainingEpsilon );
|
||||
|
||||
// Make polygon strictly simple to avoid issues (especially in 3D viewer)
|
||||
m_board_poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
|
||||
|
||||
if( !success && aErrorMsg )
|
||||
{
|
||||
*aErrorMsg = _( "Footprint outline is missing or malformed. Run Footprint Checker for "
|
||||
"a full analysis." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = m_board->GetBoardPolygonOutlines( m_board_poly );
|
||||
|
||||
if( !success && aErrorMsg )
|
||||
*aErrorMsg = _( "Board outline is missing or malformed. Run DRC for a full analysis." );
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
float BOARD_ADAPTER::GetFootprintZPos( bool aIsFlipped ) const
|
||||
{
|
||||
if( aIsFlipped )
|
||||
{
|
||||
if( m_Cfg->m_Render.show_solderpaste )
|
||||
return m_layerZcoordBottom[B_SilkS];
|
||||
else
|
||||
return m_layerZcoordBottom[B_Paste];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_Cfg->m_Render.show_solderpaste )
|
||||
return m_layerZcoordTop[F_SilkS];
|
||||
else
|
||||
return m_layerZcoordTop[F_Paste];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SFVEC4F BOARD_ADAPTER::GetLayerColor( PCB_LAYER_ID aLayerId ) const
|
||||
{
|
||||
wxASSERT( aLayerId < PCB_LAYER_ID_COUNT );
|
||||
|
||||
const COLOR4D color = m_colors->GetColor( aLayerId );
|
||||
|
||||
return SFVEC4F( color.r, color.g, color.b, color.a );
|
||||
}
|
||||
|
||||
|
||||
SFVEC4F BOARD_ADAPTER::GetItemColor( int aItemId ) const
|
||||
{
|
||||
return GetColor( m_colors->GetColor( aItemId ) );
|
||||
}
|
||||
|
||||
|
||||
SFVEC4F BOARD_ADAPTER::GetColor( const COLOR4D& aColor ) const
|
||||
{
|
||||
return SFVEC4F( aColor.r, aColor.g, aColor.b, aColor.a );
|
||||
}
|
||||
|
||||
|
||||
SFVEC2F BOARD_ADAPTER::GetSphericalCoord( int i ) const
|
||||
{
|
||||
SFVEC2F sphericalCoord =
|
||||
SFVEC2F( ( m_Cfg->m_Render.raytrace_lightElevation[i] + 90.0f ) / 180.0f,
|
||||
m_Cfg->m_Render.raytrace_lightAzimuth[i] / 180.0f );
|
||||
|
||||
sphericalCoord.x = glm::clamp( sphericalCoord.x, 0.0f, 1.0f );
|
||||
sphericalCoord.y = glm::clamp( sphericalCoord.y, 0.0f, 2.0f );
|
||||
|
||||
return sphericalCoord;
|
||||
}
|
||||
@@ -1,493 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef BOARD_ADAPTER_H
|
||||
#define BOARD_ADAPTER_H
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "../3d_rendering/raytracing/accelerators/container_2d.h"
|
||||
#include "../3d_rendering/raytracing/accelerators/container_3d.h"
|
||||
#include "../3d_rendering/raytracing/shapes3D/bbox_3d.h"
|
||||
#include "../3d_rendering/camera.h"
|
||||
#include "../3d_enums.h"
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include "../common_ogl/ogl_attr_list.h"
|
||||
#include "../3d_viewer/eda_3d_viewer_settings.h"
|
||||
|
||||
#include <layer_ids.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_base_frame.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_shape.h>
|
||||
#include <pcb_dimension.h>
|
||||
#include <zone.h>
|
||||
#include <footprint.h>
|
||||
#include <reporter.h>
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
|
||||
class COLOR_SETTINGS;
|
||||
class PCB_TEXTBOX;
|
||||
|
||||
/// A type that stores a container of 2d objects for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, BVH_CONTAINER_2D*> MAP_CONTAINER_2D_BASE;
|
||||
|
||||
/// A type that stores polysets for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, SHAPE_POLY_SET*> MAP_POLY;
|
||||
|
||||
/// This defines the range that all coord will have to be rendered.
|
||||
/// It will use this value to convert to a normalized value between
|
||||
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
|
||||
#define RANGE_SCALE_3D 8.0f
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to handle information needed to display 3D board.
|
||||
*/
|
||||
class BOARD_ADAPTER
|
||||
{
|
||||
public:
|
||||
BOARD_ADAPTER();
|
||||
|
||||
~BOARD_ADAPTER();
|
||||
|
||||
/**
|
||||
* Update the cache manager pointer.
|
||||
*
|
||||
* @param aCachePointer: the pointer to the 3D cache manager.
|
||||
*/
|
||||
void Set3dCacheManager( S3D_CACHE* aCacheMgr ) noexcept { m_3dModelManager = aCacheMgr; }
|
||||
S3D_CACHE* Get3dCacheManager() const noexcept { return m_3dModelManager; }
|
||||
|
||||
/**
|
||||
* Check if a layer is enabled.
|
||||
*
|
||||
* @param aLayer layer ID to get status.
|
||||
*/
|
||||
bool Is3dLayerEnabled( PCB_LAYER_ID aLayer ) const;
|
||||
|
||||
/**
|
||||
* Test if footprint should be displayed in relation to attributes and the flags.
|
||||
*/
|
||||
bool IsFootprintShown( FOOTPRINT_ATTR_T aFPAttributes ) const;
|
||||
|
||||
/**
|
||||
* Set current board to be rendered.
|
||||
*
|
||||
* @param aBoard board to process.
|
||||
*/
|
||||
void SetBoard( BOARD* aBoard ) noexcept { m_board = aBoard; }
|
||||
const BOARD* GetBoard() const noexcept { return m_board; }
|
||||
|
||||
void ReloadColorSettings() noexcept;
|
||||
|
||||
/**
|
||||
* Function to be called by the render when it need to reload the settings for the board.
|
||||
*
|
||||
* @param aStatusReporter the pointer for the status reporter.
|
||||
* @param aWarningReporter pointer for the warning reporter.
|
||||
*/
|
||||
void InitSettings( REPORTER* aStatusReporter, REPORTER* aWarningReporter );
|
||||
|
||||
/**
|
||||
* Board integer units To 3D units.
|
||||
*
|
||||
* @return the conversion factor to transform a position from the board to 3D units.
|
||||
*/
|
||||
double BiuTo3dUnits() const noexcept { return m_biuTo3Dunits; }
|
||||
|
||||
/**
|
||||
* Get the board outling bounding box.
|
||||
*
|
||||
* @return the board bounding box in 3D units.
|
||||
*/
|
||||
const BBOX_3D& GetBBox() const noexcept { return m_boardBoundingBox; }
|
||||
|
||||
/**
|
||||
* Get the board body thickness, including internal copper layers (in 3D units).
|
||||
*/
|
||||
float GetBoardBodyThickness() const noexcept { return m_boardBodyThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the non copper layers thickness (in 3D units).
|
||||
*/
|
||||
float GetNonCopperLayerThickness() const noexcept { return m_nonCopperLayerThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the copper layer thicknesses (in 3D units).
|
||||
*/
|
||||
float GetFrontCopperThickness() const noexcept { return m_frontCopperThickness3DU; }
|
||||
float GetBackCopperThickness() const noexcept { return m_backCopperThickness3DU; }
|
||||
|
||||
/**
|
||||
* Get the hole plating thickness (NB: in BOARD UNITS!).
|
||||
*/
|
||||
int GetHolePlatingThickness() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the board size.
|
||||
*
|
||||
* @return size in BIU units.
|
||||
*/
|
||||
VECTOR2I GetBoardSize() const noexcept { return m_boardSize; }
|
||||
|
||||
/**
|
||||
* Get the board center.
|
||||
*
|
||||
* @return position in BIU units.
|
||||
*/
|
||||
VECTOR2I GetBoardPos() const noexcept { return m_boardPos; }
|
||||
|
||||
/**
|
||||
* The board center position in 3D units.
|
||||
*
|
||||
* @return board center vector position in 3D units.
|
||||
*/
|
||||
const SFVEC3F& GetBoardCenter() const noexcept { return m_boardCenter; }
|
||||
|
||||
/**
|
||||
* Get the position of the footprint in 3d integer units considering if it is flipped or not.
|
||||
*
|
||||
* @param aIsFlipped true for use in footprints on Front (top) layer, false
|
||||
* if footprint is on back (bottom) layer.
|
||||
* @return the Z position of 3D shapes, in 3D integer units.
|
||||
*/
|
||||
float GetFootprintZPos( bool aIsFlipped ) const ;
|
||||
|
||||
/**
|
||||
* Get the current polygon of the epoxy board.
|
||||
*
|
||||
* @return the shape polygon
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetBoardPoly() const noexcept { return m_board_poly; }
|
||||
|
||||
/**
|
||||
* Get the technical color of a layer.
|
||||
*
|
||||
* @param aLayerId the layer to get the color information.
|
||||
* @return the color in SFVEC3F format.
|
||||
*/
|
||||
SFVEC4F GetLayerColor( PCB_LAYER_ID aLayerId ) const;
|
||||
|
||||
/**
|
||||
* Get the technical color of a layer.
|
||||
*
|
||||
* @param aItemId the item id to get the color information.
|
||||
* @return the color in SFVEC3F format.
|
||||
*/
|
||||
SFVEC4F GetItemColor( int aItemId ) const;
|
||||
|
||||
/**
|
||||
* @param[in] aColor is the color mapped.
|
||||
* @return the color in SFVEC3F format
|
||||
*/
|
||||
SFVEC4F GetColor( const COLOR4D& aColor ) const;
|
||||
|
||||
SFVEC2F GetSphericalCoord( int i ) const;
|
||||
|
||||
/**
|
||||
* Get the top z position.
|
||||
*
|
||||
* @param aLayerId layer id.
|
||||
* @return position in 3D units.
|
||||
*/
|
||||
float GetLayerTopZPos( PCB_LAYER_ID aLayerId ) const noexcept
|
||||
{
|
||||
return m_layerZcoordTop[aLayerId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bottom z position.
|
||||
*
|
||||
* @param aLayerId layer id.
|
||||
* @return position in 3D units.
|
||||
*/
|
||||
float GetLayerBottomZPos( PCB_LAYER_ID aLayerId ) const noexcept
|
||||
{
|
||||
return m_layerZcoordBottom[aLayerId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of containers that have the objects per layer.
|
||||
*
|
||||
* @return the map containers of this board.
|
||||
*/
|
||||
const MAP_CONTAINER_2D_BASE& GetLayerMap() const noexcept { return m_layerMap; }
|
||||
const BVH_CONTAINER_2D* GetPlatedPadsFront() const noexcept { return m_platedPadsFront; }
|
||||
const BVH_CONTAINER_2D* GetPlatedPadsBack() const noexcept { return m_platedPadsBack; }
|
||||
|
||||
const MAP_CONTAINER_2D_BASE& GetLayerHoleMap() const noexcept { return m_layerHoleMap; }
|
||||
const BVH_CONTAINER_2D& GetThroughHoleIds() const noexcept { return m_throughHoleIds; }
|
||||
const BVH_CONTAINER_2D& GetThroughHoleOds() const noexcept { return m_throughHoleOds; }
|
||||
|
||||
/**
|
||||
* Get through hole outside diameter 2D polygons.
|
||||
*
|
||||
* The outside diameter 2D polygon is the hole diameter plus the plating thickness.
|
||||
*
|
||||
* @return a container with through hold outside diameter 2D polygons.
|
||||
*/
|
||||
const SHAPE_POLY_SET& GetThroughHoleOdPolys() const noexcept
|
||||
{
|
||||
return m_throughHoleOdPolys;
|
||||
}
|
||||
|
||||
const BVH_CONTAINER_2D& GetThroughHoleAnnularRings() const noexcept
|
||||
{
|
||||
return m_throughHoleAnnularRings;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetThroughHoleAnnularRingPolys() const noexcept
|
||||
{
|
||||
return m_throughHoleAnnularRingPolys;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetOuterNonPlatedThroughHolePoly() const noexcept
|
||||
{
|
||||
return m_nonPlatedThroughHoleOdPolys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a container with through hole via hole outside diameters.
|
||||
*/
|
||||
const BVH_CONTAINER_2D& GetThroughHoleViaOds() const noexcept
|
||||
{
|
||||
return m_throughHoleViaOds;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetThroughHoleViaOdPolys() const noexcept
|
||||
{
|
||||
return m_throughHoleViaOdPolys;
|
||||
}
|
||||
|
||||
unsigned int GetViaCount() const noexcept { return m_viaCount; }
|
||||
unsigned int GetHoleCount() const noexcept { return m_holeCount; }
|
||||
|
||||
/**
|
||||
* @return via hole average diameter dimension in 3D units.
|
||||
*/
|
||||
float GetAverageViaHoleDiameter() const noexcept { return m_averageViaHoleDiameter; }
|
||||
|
||||
/**
|
||||
* @return the average diameter of through holes in 3D units.
|
||||
*/
|
||||
float GetAverageHoleDiameter() const noexcept { return m_averageHoleDiameter; }
|
||||
|
||||
/**
|
||||
* @return average track width in 3D units.
|
||||
*/
|
||||
float GetAverageTrackWidth() const noexcept { return m_averageTrackWidth; }
|
||||
|
||||
/**
|
||||
* @param aDiameter3DU diameter in 3DU.
|
||||
* @return number of sides that should be used in a circle with \a aDiameter3DU.
|
||||
*/
|
||||
unsigned int GetCircleSegmentCount( float aDiameter3DU ) const;
|
||||
|
||||
/**
|
||||
* @param aDiameterBIU diameter in board internal units.
|
||||
* @return number of sides that should be used in circle with \a aDiameterBIU.
|
||||
*/
|
||||
unsigned int GetCircleSegmentCount( int aDiameterBIU ) const;
|
||||
|
||||
/**
|
||||
* Get map of polygon's layers.
|
||||
*
|
||||
* @return the map with polygon's layers.
|
||||
*/
|
||||
const MAP_POLY& GetPolyMap() const noexcept { return m_layers_poly; }
|
||||
|
||||
const SHAPE_POLY_SET* GetFrontPlatedPadPolys() { return m_frontPlatedPadPolys; }
|
||||
const SHAPE_POLY_SET* GetBackPlatedPadPolys() { return m_backPlatedPadPolys; }
|
||||
const MAP_POLY& GetHoleIdPolysMap() const noexcept { return m_layerHoleIdPolys; }
|
||||
const MAP_POLY& GetHoleOdPolysMap() const noexcept { return m_layerHoleOdPolys; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Create the board outline polygon.
|
||||
*
|
||||
* @return false if the outline could not be created
|
||||
*/
|
||||
bool createBoardPolygon( wxString* aErrorMsg );
|
||||
void createLayers( REPORTER* aStatusReporter );
|
||||
void destroyLayers();
|
||||
|
||||
// Helper functions to create the board
|
||||
void createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer );
|
||||
|
||||
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;
|
||||
|
||||
OBJECT_2D* createPadWithDrill( const PAD* aPad, int aInflateValue );
|
||||
|
||||
void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads );
|
||||
|
||||
void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aItem );
|
||||
|
||||
void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
void transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
|
||||
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, int aWidth,
|
||||
CONTAINER_2D_BASE* aDstContainer, const BOARD_ITEM& aOwner );
|
||||
|
||||
void buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, int aWidth );
|
||||
|
||||
// Helper functions to create poly contours
|
||||
void buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& aBuffer, int aWidth) const;
|
||||
|
||||
void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aBuffer ) const;
|
||||
|
||||
public:
|
||||
static CUSTOM_COLORS_LIST g_SilkscreenColors;
|
||||
static CUSTOM_COLORS_LIST g_MaskColors;
|
||||
static CUSTOM_COLORS_LIST g_PasteColors;
|
||||
static CUSTOM_COLORS_LIST g_FinishColors;
|
||||
static CUSTOM_COLORS_LIST g_BoardColors;
|
||||
|
||||
static KIGFX::COLOR4D g_DefaultBackgroundTop;
|
||||
static KIGFX::COLOR4D g_DefaultBackgroundBot;
|
||||
static KIGFX::COLOR4D g_DefaultSilkscreen;
|
||||
static KIGFX::COLOR4D g_DefaultSolderMask;
|
||||
static KIGFX::COLOR4D g_DefaultSolderPaste;
|
||||
static KIGFX::COLOR4D g_DefaultSurfaceFinish;
|
||||
static KIGFX::COLOR4D g_DefaultBoardBody;
|
||||
|
||||
public:
|
||||
EDA_3D_VIEWER_SETTINGS* m_Cfg;
|
||||
|
||||
bool m_IsBoardView;
|
||||
bool m_MousewheelPanning;
|
||||
bool m_IsPreviewer; ///< true if the board adaptater is living in a 3D
|
||||
///< preview panel, false for the standard 3D viewer
|
||||
|
||||
SFVEC4F m_BgColorBot; ///< background bottom color
|
||||
SFVEC4F m_BgColorTop; ///< background top color
|
||||
SFVEC4F m_BoardBodyColor; ///< in realistic mode: FR4 board color
|
||||
SFVEC4F m_SolderMaskColorBot; ///< in realistic mode: solder mask color ( bot )
|
||||
SFVEC4F m_SolderMaskColorTop; ///< in realistic mode: solder mask color ( top )
|
||||
SFVEC4F m_SolderPasteColor; ///< in realistic mode: solder paste color
|
||||
SFVEC4F m_SilkScreenColorBot; ///< in realistic mode: SilkScreen color ( bot )
|
||||
SFVEC4F m_SilkScreenColorTop; ///< in realistic mode: SilkScreen color ( top )
|
||||
SFVEC4F m_CopperColor; ///< in realistic mode: copper color
|
||||
|
||||
private:
|
||||
BOARD* m_board;
|
||||
S3D_CACHE* m_3dModelManager;
|
||||
RENDER_SETTINGS* m_renderSettings;
|
||||
COLOR_SETTINGS* m_colors;
|
||||
|
||||
VECTOR2I m_boardPos; ///< Board center position in board internal units.
|
||||
VECTOR2I m_boardSize; ///< Board size in board internal units.
|
||||
SFVEC3F m_boardCenter; ///< 3D center position of the board in 3D units.
|
||||
BBOX_3D m_boardBoundingBox; ///< 3D bounding box of the board in 3D units.
|
||||
|
||||
MAP_POLY m_layers_poly; ///< Amalgamated polygon contours for various types of
|
||||
///< items
|
||||
|
||||
SHAPE_POLY_SET* m_frontPlatedPadPolys;
|
||||
SHAPE_POLY_SET* m_backPlatedPadPolys;
|
||||
|
||||
MAP_POLY m_layerHoleOdPolys; ///< Hole outer diameters (per layer)
|
||||
MAP_POLY m_layerHoleIdPolys; ///< Hole inner diameters (per layer)
|
||||
|
||||
SHAPE_POLY_SET m_nonPlatedThroughHoleOdPolys; ///< NPTH outer diameters
|
||||
SHAPE_POLY_SET m_throughHoleOdPolys; ///< PTH outer diameters
|
||||
SHAPE_POLY_SET m_throughHoleViaOdPolys; ///< Via hole outer diameters
|
||||
SHAPE_POLY_SET m_throughHoleAnnularRingPolys; ///< Via annular ring outer diameters
|
||||
|
||||
SHAPE_POLY_SET m_board_poly; ///< Board outline polygon.
|
||||
|
||||
MAP_CONTAINER_2D_BASE m_layerMap; ///< 2D elements for each layer.
|
||||
MAP_CONTAINER_2D_BASE m_layerHoleMap; ///< Holes for each layer.
|
||||
|
||||
BVH_CONTAINER_2D* m_platedPadsFront;
|
||||
BVH_CONTAINER_2D* m_platedPadsBack;
|
||||
|
||||
BVH_CONTAINER_2D m_throughHoleOds; ///< List of PTH outer diameters
|
||||
BVH_CONTAINER_2D m_throughHoleIds; ///< List of PTH inner diameters
|
||||
BVH_CONTAINER_2D m_throughHoleAnnularRings; ///< List of via annular rings
|
||||
BVH_CONTAINER_2D m_throughHoleViaOds; ///< List of via hole outer diameters
|
||||
BVH_CONTAINER_2D m_throughHoleViaIds; ///< List of via hole inner diameters
|
||||
|
||||
unsigned int m_copperLayersCount;
|
||||
|
||||
double m_biuTo3Dunits; ///< Scale factor to convert board internal units to
|
||||
///< 3D units normalized between -1.0 and 1.0.
|
||||
|
||||
std::array<float, PCB_LAYER_ID_COUNT> m_layerZcoordTop; ///< Top (End) Z position of each
|
||||
///< layer in 3D units.
|
||||
|
||||
std::array<float, PCB_LAYER_ID_COUNT> m_layerZcoordBottom; ///< Bottom (Start) Z position of
|
||||
///< each layer in 3D units.
|
||||
|
||||
float m_frontCopperThickness3DU;
|
||||
float m_backCopperThickness3DU;
|
||||
float m_boardBodyThickness3DU;
|
||||
float m_nonCopperLayerThickness3DU;
|
||||
float m_solderPasteLayerThickness3DU;
|
||||
|
||||
unsigned int m_trackCount;
|
||||
float m_averageTrackWidth;
|
||||
unsigned int m_viaCount;
|
||||
float m_averageViaHoleDiameter;
|
||||
unsigned int m_holeCount;
|
||||
float m_averageHoleDiameter;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable debug output for this class. Output can be turned
|
||||
* on by setting the WXTRACE environment variable to "KI_TRACE_EDA_CINFO3D_VISU". See the
|
||||
* wxWidgets documentation on wxLogTrace for more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class EDA_3D_BOARD_HOLDER
|
||||
{
|
||||
public:
|
||||
virtual BOARD_ADAPTER& GetAdapter() = 0;
|
||||
virtual CAMERA& GetCurrentCamera() = 0;
|
||||
|
||||
virtual ~EDA_3D_BOARD_HOLDER() {};
|
||||
};
|
||||
|
||||
#endif // BOARD_ADAPTER_H
|
||||
@@ -1,849 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file create_graphic_brd_items.cpp
|
||||
* @brief This file implements the creation of 2D graphic primitives of pcb items:
|
||||
* pads, tracks, drawsegments, texts....
|
||||
* It is based on the function found in the files:
|
||||
* board_items_to_polygon_shape_transform.cpp
|
||||
*/
|
||||
|
||||
#include "../3d_rendering/raytracing/shapes2D/ring_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/round_segment_2d.h"
|
||||
#include "../3d_rendering/raytracing/shapes2D/triangle_2d.h"
|
||||
#include "fp_textbox.h"
|
||||
#include <board_adapter.h>
|
||||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_text.h>
|
||||
#include <fp_shape.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
|
||||
#include <zone.h>
|
||||
#include <fp_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <geometry/shape_rect.h>
|
||||
#include <geometry/shape_simple.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/log.h>
|
||||
#include <macros.h>
|
||||
#include <callback_gal.h>
|
||||
|
||||
|
||||
#define TO_3DU( x ) ( ( x ) * m_biuTo3Dunits )
|
||||
|
||||
#define TO_SFVEC2F( vec ) SFVEC2F( TO_3DU( vec.x ), TO_3DU( -vec.y ) )
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aItem )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
float penWidth_3DU = TO_3DU( aText->GetEffectiveTextPenWidth() );
|
||||
KIFONT::FONT* font = aText->GetFont();
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
|
||||
|
||||
if( aItem && aItem->IsKnockout() )
|
||||
{
|
||||
int maxError = m_board->GetDesignSettings().m_MaxError;
|
||||
SHAPE_POLY_SET finalPoly;
|
||||
|
||||
if( aItem->Type() == PCB_FP_TEXT_T )
|
||||
{
|
||||
static_cast<const FP_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, maxError,
|
||||
ERROR_INSIDE );
|
||||
}
|
||||
else if( aItem->Type() == PCB_TEXT_T )
|
||||
{
|
||||
static_cast<const PCB_TEXT*>( aItem )->TransformTextToPolySet( finalPoly, 0, maxError,
|
||||
ERROR_INSIDE );
|
||||
}
|
||||
|
||||
// Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
|
||||
// if needed, and Fracture() called twice can create bad results and is useless
|
||||
ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
CALLBACK_GAL callback_gal( empty_opts,
|
||||
// Stroke callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
|
||||
{
|
||||
const SFVEC2F pt1_3DU = TO_SFVEC2F( aPt1 );
|
||||
const SFVEC2F pt2_3DU = TO_SFVEC2F( aPt2 );
|
||||
|
||||
if( penWidth_3DU == 0.0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( pt1_3DU, pt2_3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth_3DU / 2,
|
||||
*aItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( pt1_3DU, pt2_3DU, penWidth_3DU,
|
||||
*aItem ) );
|
||||
}
|
||||
},
|
||||
// Triangulation callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
|
||||
{
|
||||
aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
|
||||
TO_SFVEC2F( aPt3 ), *aItem ) );
|
||||
} );
|
||||
|
||||
attrs.m_Angle = aText->GetDrawRotation();
|
||||
|
||||
font->Draw( &callback_gal, aText->GetShownText( true ), aText->GetDrawPos(), attrs );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aDimension, aContainer, aDimension );
|
||||
|
||||
const int linewidth = aDimension->GetLineThickness();
|
||||
|
||||
for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
|
||||
{
|
||||
switch( shape->Type() )
|
||||
{
|
||||
case SH_SEGMENT:
|
||||
{
|
||||
const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
|
||||
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ),
|
||||
TO_3DU( linewidth ), *aOwner ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_CIRCLE:
|
||||
{
|
||||
int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
|
||||
int delta = aDimension->GetLineThickness() / 2;
|
||||
|
||||
aContainer->Add( new RING_2D( TO_SFVEC2F( shape->Centre() ), TO_3DU( radius - delta ),
|
||||
TO_3DU( radius + delta ), *aOwner ) );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
|
||||
if( aFootprint->Reference().GetLayer() == aLayerId && aFootprint->Reference().IsVisible() )
|
||||
addText( &aFootprint->Reference(), aContainer, &aFootprint->Reference() );
|
||||
|
||||
if( aFootprint->Value().GetLayer() == aLayerId && aFootprint->Value().IsVisible() )
|
||||
addText( &aFootprint->Value(), aContainer, &aFootprint->Value() );
|
||||
|
||||
for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_FP_TEXT_T:
|
||||
{
|
||||
FP_TEXT* text = static_cast<FP_TEXT*>( item );
|
||||
|
||||
if( text->GetLayer() == aLayerId && text->IsVisible() )
|
||||
addText( text, aContainer, text );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_FP_TEXTBOX_T:
|
||||
{
|
||||
FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
|
||||
|
||||
if( textbox->GetLayer() == aLayerId )
|
||||
{
|
||||
if( textbox->IsBorderEnabled() )
|
||||
addShape( textbox, aContainer, aFootprint );
|
||||
addText( textbox, aContainer, aFootprint );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_FP_DIM_ALIGNED_T:
|
||||
case PCB_FP_DIM_CENTER_T:
|
||||
case PCB_FP_DIM_ORTHOGONAL_T:
|
||||
case PCB_FP_DIM_RADIAL_T:
|
||||
case PCB_FP_DIM_LEADER_T:
|
||||
{
|
||||
PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
|
||||
|
||||
if( dimension->GetLayer() == aLayerId )
|
||||
addShape( dimension, aContainer, aFootprint );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_FP_SHAPE_T:
|
||||
{
|
||||
FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
|
||||
|
||||
if( shape->GetLayer() == aLayerId )
|
||||
addShape( shape, aContainer, aFootprint );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer )
|
||||
{
|
||||
SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
|
||||
SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
|
||||
|
||||
switch( aTrack->Type() )
|
||||
{
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
const float radius3DU = TO_3DU( aTrack->GetWidth() / 2 );
|
||||
|
||||
if( radius3DU > 0.0 )
|
||||
aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
|
||||
|
||||
if( arc->IsDegenerated() )
|
||||
{
|
||||
// Draw this very small arc like a track segment (a PCB_TRACE_T)
|
||||
PCB_TRACK track( arc->GetParent() );
|
||||
track.SetStart( arc->GetStart() );
|
||||
track.SetEnd( arc->GetEnd() );
|
||||
track.SetWidth( arc->GetWidth() );
|
||||
track.SetLayer( arc->GetLayer() );
|
||||
|
||||
createTrack( &track, aDstContainer );
|
||||
return;
|
||||
}
|
||||
|
||||
VECTOR2D center( arc->GetCenter() );
|
||||
EDA_ANGLE arc_angle = arc->GetAngle();
|
||||
double radius = arc->GetRadius();
|
||||
int arcsegcount = GetArcToSegmentCount( radius, ARC_HIGH_DEF, arc_angle );
|
||||
int circlesegcount;
|
||||
|
||||
// Avoid arcs that cannot be drawn
|
||||
if( radius < std::numeric_limits<double>::min() || arc_angle.IsZero() )
|
||||
break;
|
||||
|
||||
// We need a circle to segment count. However, the arc angle can be small, and the
|
||||
// radius very big. so we calculate a reasonable value for circlesegcount.
|
||||
if( arcsegcount <= 1 ) // The arc will be approximated by a segment
|
||||
{
|
||||
circlesegcount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
circlesegcount = KiROUND( arcsegcount * 360.0 / std::abs( arc_angle.AsDegrees() ) );
|
||||
circlesegcount = std::max( 1, std::min( circlesegcount, 128 ) );
|
||||
}
|
||||
|
||||
transformArcToSegments( VECTOR2I( center.x, center.y ), arc->GetStart(), arc_angle,
|
||||
circlesegcount, arc->GetWidth(), aDstContainer, *arc );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_TRACE_T: // Track is a usual straight segment
|
||||
{
|
||||
if( aTrack->GetWidth() == 0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aTrack->GetWidth() / 2 ),
|
||||
*aTrack ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aTrack->GetWidth() ),
|
||||
*aTrack ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const
|
||||
{
|
||||
SHAPE_POLY_SET poly;
|
||||
int maxError = GetBoard()->GetDesignSettings().m_MaxError;
|
||||
VECTOR2I clearance = aMargin;
|
||||
|
||||
// Our shape-based builder can't handle negative or differing x:y clearance values (the
|
||||
// former are common for solder paste while the later get generated when a relative paste
|
||||
// margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
|
||||
// run the general-purpose polygon builder on.
|
||||
// Of course being a hack it falls down when dealing with custom shape pads (where the size
|
||||
// is only the size of the anchor), so for those we punt and just use aMargin.x.
|
||||
|
||||
if( ( clearance.x < 0 || clearance.x != clearance.y )
|
||||
&& aPad->GetShape() != PAD_SHAPE::CUSTOM )
|
||||
{
|
||||
VECTOR2I dummySize = VECTOR2I( aPad->GetSize() ) + clearance + clearance;
|
||||
|
||||
if( dummySize.x <= 0 || dummySize.y <= 0 )
|
||||
return;
|
||||
|
||||
PAD dummy( *aPad );
|
||||
dummy.SetSize( wxSize( dummySize.x, dummySize.y ) );
|
||||
dummy.TransformShapeToPolygon( poly, aLayer, 0, maxError, ERROR_INSIDE );
|
||||
clearance = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
auto padShapes = std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
|
||||
|
||||
for( const SHAPE* shape : padShapes->Shapes() )
|
||||
{
|
||||
switch( shape->Type() )
|
||||
{
|
||||
case SH_SEGMENT:
|
||||
{
|
||||
const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( shape );
|
||||
|
||||
const SFVEC2F a3DU = TO_SFVEC2F( seg->GetSeg().A );
|
||||
const SFVEC2F b3DU = TO_SFVEC2F( seg->GetSeg().B );
|
||||
const double width3DU = TO_3DU( seg->GetWidth() + clearance.x * 2 );
|
||||
|
||||
if( width3DU == 0.0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( a3DU, b3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_CIRCLE:
|
||||
{
|
||||
const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
|
||||
|
||||
const double radius3DU = TO_3DU( circle->GetRadius() + clearance.x );
|
||||
const SFVEC2F center3DU = TO_SFVEC2F( circle->GetCenter() );
|
||||
|
||||
// Don't render zero radius circles
|
||||
if( radius3DU > 0.0 )
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_RECT:
|
||||
{
|
||||
const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
|
||||
|
||||
poly.NewOutline();
|
||||
poly.Append( rect->GetPosition() );
|
||||
poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
|
||||
poly.Append( rect->GetPosition() + rect->GetSize() );
|
||||
poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_SIMPLE:
|
||||
poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
|
||||
break;
|
||||
|
||||
case SH_POLY_SET:
|
||||
poly = *(SHAPE_POLY_SET*) shape;
|
||||
break;
|
||||
|
||||
case SH_ARC:
|
||||
{
|
||||
const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
|
||||
SHAPE_LINE_CHAIN l = arc->ConvertToPolyline( maxError );
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
{
|
||||
SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() );
|
||||
const SFVEC2F a3DU = TO_SFVEC2F( seg.GetSeg().A );
|
||||
const SFVEC2F b3DU = TO_SFVEC2F( seg.GetSeg().B );
|
||||
const double width3DU = TO_3DU( arc->GetWidth() + clearance.x * 2 );
|
||||
|
||||
if( width3DU == 0.0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( a3DU, b3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !poly.IsEmpty() )
|
||||
{
|
||||
if( clearance.x )
|
||||
poly.Inflate( clearance.x, 32 );
|
||||
|
||||
// Add the PAD polygon
|
||||
ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue )
|
||||
{
|
||||
if( !aPad->HasHole() )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithDrill - found an invalid pad" ) );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
|
||||
|
||||
if( slot->GetSeg().A == slot->GetSeg().B )
|
||||
{
|
||||
return new FILLED_CIRCLE_2D( TO_SFVEC2F( slot->GetSeg().A ),
|
||||
TO_3DU( slot->GetWidth() / 2 + aInflateValue ),
|
||||
*aPad );
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ROUND_SEGMENT_2D( TO_SFVEC2F( slot->GetSeg().A ),
|
||||
TO_SFVEC2F( slot->GetSeg().B ),
|
||||
TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
|
||||
*aPad );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads )
|
||||
{
|
||||
for( PAD* pad : aFootprint->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
if( IsCopperLayer( aLayerId ) )
|
||||
{
|
||||
// Skip pad annulus when there isn't one (note: this is more discerning than
|
||||
// pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume
|
||||
// the entire pad).
|
||||
if( !pad->IsOnCopperLayer() )
|
||||
continue;
|
||||
|
||||
// Skip pad annulus when not connected on this layer (if removing is enabled)
|
||||
if( !pad->FlashLayer( aLayerId ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
VECTOR2I margin( 0, 0 );
|
||||
|
||||
switch( aLayerId )
|
||||
{
|
||||
case F_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case B_Cu:
|
||||
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case F_Mask:
|
||||
case B_Mask:
|
||||
margin.x += pad->GetSolderMaskExpansion();
|
||||
margin.y += pad->GetSolderMaskExpansion();
|
||||
break;
|
||||
|
||||
case F_Paste:
|
||||
case B_Paste:
|
||||
margin += pad->GetSolderPasteMargin();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
createPadWithMargin( pad, aContainer, aLayerId, margin );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// based on TransformArcToPolygon function from
|
||||
// common/convert_basic_shapes_to_polygon.cpp
|
||||
void BOARD_ADAPTER::transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
|
||||
const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount,
|
||||
int aWidth, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM& aOwner )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
if( aWidth == 0 )
|
||||
return;
|
||||
|
||||
VECTOR2I arc_start, arc_end;
|
||||
EDA_ANGLE arcAngle( aArcAngle );
|
||||
EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
|
||||
|
||||
arc_end = arc_start = aStart;
|
||||
|
||||
if( arcAngle != ANGLE_360 )
|
||||
RotatePoint( arc_end, aCentre, -arcAngle );
|
||||
|
||||
if( arcAngle < ANGLE_0 )
|
||||
{
|
||||
std::swap( arc_start, arc_end );
|
||||
arcAngle = -arcAngle;
|
||||
}
|
||||
|
||||
// Compute the ends of segments and creates poly
|
||||
VECTOR2I curr_end = arc_start;
|
||||
VECTOR2I curr_start = arc_start;
|
||||
|
||||
for( EDA_ANGLE ii = delta; ii < arcAngle; ii += delta )
|
||||
{
|
||||
curr_end = arc_start;
|
||||
RotatePoint( curr_end, aCentre, -ii );
|
||||
|
||||
const SFVEC2F start3DU = TO_SFVEC2F( curr_start );
|
||||
const SFVEC2F end3DU = TO_SFVEC2F( curr_end );
|
||||
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) );
|
||||
else
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) );
|
||||
|
||||
curr_start = curr_end;
|
||||
}
|
||||
|
||||
if( curr_end != arc_end )
|
||||
{
|
||||
const SFVEC2F start3DU = TO_SFVEC2F( curr_end );
|
||||
const SFVEC2F end3DU = TO_SFVEC2F( arc_end );
|
||||
|
||||
if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) );
|
||||
else
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
// The full width of the lines to create
|
||||
// The extra 1 protects the inner/outer radius values from degeneracy
|
||||
const int linewidth = aShape->GetWidth() + 1;
|
||||
PLOT_DASH_TYPE lineStyle = aShape->GetStroke().GetPlotStyle();
|
||||
|
||||
if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE )
|
||||
{
|
||||
switch( aShape->GetShape() )
|
||||
{
|
||||
case SHAPE_T::CIRCLE:
|
||||
{
|
||||
const SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() );
|
||||
float inner_radius3DU = TO_3DU( aShape->GetRadius() - linewidth / 2 );
|
||||
float outer_radius3DU = TO_3DU( aShape->GetRadius() + linewidth / 2 );
|
||||
|
||||
if( inner_radius3DU < 0 )
|
||||
inner_radius3DU = 0.0;
|
||||
|
||||
if( aShape->IsFilled() )
|
||||
{
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius3DU,
|
||||
*aOwner ) );
|
||||
}
|
||||
else if( outer_radius3DU > inner_radius3DU )
|
||||
{
|
||||
aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU,
|
||||
*aOwner ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
if( aShape->IsFilled() )
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
|
||||
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
|
||||
TO_3DU( linewidth ), *aOwner ) );
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
|
||||
TO_3DU( linewidth ), *aOwner ) );
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
|
||||
TO_3DU( linewidth ), *aOwner ) );
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
|
||||
TO_3DU( linewidth ), *aOwner ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
{
|
||||
unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
|
||||
|
||||
transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
|
||||
segCount, linewidth, aContainer, *aOwner );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::SEGMENT:
|
||||
{
|
||||
const SFVEC2F start3DU = TO_SFVEC2F( aShape->GetStart() );
|
||||
const SFVEC2F end3DU = TO_SFVEC2F( aShape->GetEnd() );
|
||||
const double linewidth3DU = TO_3DU( linewidth );
|
||||
|
||||
if( linewidth3DU == 0.0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, linewidth3DU / 2, *aOwner ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth3DU, *aOwner ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
case SHAPE_T::POLY:
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
// Some polygons can be a bit complex (especially when coming from a
|
||||
// picture ot a text converted to a polygon
|
||||
// So call Simplify before calling ConvertPolygonToTriangles, just in case.
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
if( polyList.IsEmpty() ) // Just for caution
|
||||
break;
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
|
||||
+ aShape->SHAPE_T_asString() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( linewidth > 0 )
|
||||
{
|
||||
std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
|
||||
SFVEC2F a3DU;
|
||||
SFVEC2F b3DU;
|
||||
double width3DU = TO_3DU( linewidth );
|
||||
|
||||
const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
|
||||
KIGFX::PCB_RENDER_SETTINGS renderSettings;
|
||||
|
||||
renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
|
||||
renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
{
|
||||
STROKE_PARAMS::Stroke( shape, lineStyle, linewidth, &renderSettings,
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
a3DU = TO_SFVEC2F( a );
|
||||
b3DU = TO_SFVEC2F( b );
|
||||
|
||||
if( Is_segment_a_circle( a3DU, b3DU ) )
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aOwner ) );
|
||||
else
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aOwner ) );
|
||||
} );
|
||||
}
|
||||
|
||||
for( SHAPE* shape : shapes )
|
||||
delete shape;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aTextBox, aContainer, aOwner );
|
||||
|
||||
if( !aTextBox->IsBorderEnabled() )
|
||||
return;
|
||||
|
||||
// We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
|
||||
// as filled polygon even if there's no background colour.
|
||||
// So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
|
||||
|
||||
if( aTextBox->GetShape() == SHAPE_T::RECT )
|
||||
addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner );
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0,
|
||||
ARC_HIGH_DEF, ERROR_INSIDE );
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
// This convert the poly in outline and holes
|
||||
ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer,
|
||||
m_biuTo3Dunits, *aZone );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aContainer,
|
||||
int aWidth )
|
||||
{
|
||||
if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring
|
||||
{
|
||||
const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos() );
|
||||
const int radius = aPad->GetSize().x / 2;
|
||||
const float inner_radius3DU = TO_3DU( radius - aWidth / 2 );
|
||||
const float outer_radius3DU = TO_3DU( radius + aWidth / 2 );
|
||||
|
||||
aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aPad ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int j = 0; j < path.PointCount(); j++ )
|
||||
{
|
||||
SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
|
||||
SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
|
||||
|
||||
if( aWidth == 0 )
|
||||
{
|
||||
// Don't attempt to render degenerate shapes
|
||||
}
|
||||
else if( Is_segment_a_circle( start3DU, end3DU ) )
|
||||
{
|
||||
// Cannot add segments that have the same start and end point
|
||||
aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), *aPad ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), *aPad ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file create_layer_poly.cpp
|
||||
* @brief This file implements the creation of the pcb board items in the poly
|
||||
* contours format.
|
||||
*/
|
||||
|
||||
#include "board_adapter.h"
|
||||
#include <board_design_settings.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <fp_shape.h>
|
||||
#include <footprint.h>
|
||||
|
||||
|
||||
/*
|
||||
* This is used to draw pad outlines on silk layers.
|
||||
*/
|
||||
void BOARD_ADAPTER::buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& aBuffer,
|
||||
int aWidth ) const
|
||||
{
|
||||
int maxError = m_board->GetDesignSettings().m_MaxError;
|
||||
|
||||
if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring
|
||||
{
|
||||
TransformRingToPolygon( aBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, aWidth, maxError,
|
||||
ERROR_INSIDE );
|
||||
return;
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int ii = 0; ii < path.PointCount(); ++ii )
|
||||
{
|
||||
const VECTOR2I& a = path.CPoint( ii );
|
||||
const VECTOR2I& b = path.CPoint( ii + 1 );
|
||||
|
||||
TransformOvalToPolygon( aBuffer, a, b, aWidth, maxError, ERROR_INSIDE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
|
||||
SHAPE_POLY_SET& aBuffer ) const
|
||||
{
|
||||
int maxError = m_board->GetDesignSettings().m_MaxError;
|
||||
|
||||
for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
|
||||
{
|
||||
if( item->Type() == PCB_FP_SHAPE_T )
|
||||
{
|
||||
FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
|
||||
|
||||
if( shape->GetLayer() == aLayer )
|
||||
shape->TransformShapeToPolygon( aBuffer, aLayer, 0, maxError, ERROR_INSIDE );
|
||||
}
|
||||
else if( BaseType( item->Type() ) == PCB_DIMENSION_T )
|
||||
{
|
||||
PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
|
||||
|
||||
if( dimension->GetLayer() == aLayer )
|
||||
dimension->TransformShapeToPolygon( aBuffer, aLayer, 0, maxError, ERROR_INSIDE );
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef EDA_3D_CANVAS_H
|
||||
#define EDA_3D_CANVAS_H
|
||||
|
||||
#include <atomic>
|
||||
#include "board_adapter.h"
|
||||
#include "3d_rendering/raytracing/accelerators/accelerator_3d.h"
|
||||
#include "3d_rendering/render_3d_base.h"
|
||||
#include "3d_cache/3d_cache.h"
|
||||
#include <gal/hidpi_gl_3D_canvas.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
|
||||
class WX_INFOBAR;
|
||||
class wxStatusBar;
|
||||
class BOARD;
|
||||
class RENDER_3D_RAYTRACE;
|
||||
class RENDER_3D_OPENGL;
|
||||
|
||||
|
||||
/**
|
||||
* Implement a canvas based on a wxGLCanvas
|
||||
*/
|
||||
class EDA_3D_CANVAS : public HIDPI_GL_3D_CANVAS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new 3D Canvas with an attribute list.
|
||||
*
|
||||
* @param aParent the parent creator of this canvas.
|
||||
* @param aAttribList a list of openGL options created by GetOpenGL_AttributesList.
|
||||
* @param aBoard The board.
|
||||
* @param aSettings the settings options to be used by this canvas.
|
||||
*/
|
||||
EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList,
|
||||
BOARD_ADAPTER& aSettings, CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
|
||||
|
||||
~EDA_3D_CANVAS();
|
||||
|
||||
/**
|
||||
* Set a dispatcher that processes events and forwards them to tools.
|
||||
*
|
||||
* #DRAW_PANEL_GAL does not take over the ownership. Passing NULL disconnects all event
|
||||
* handlers from the DRAW_PANEL_GAL and parent frame.
|
||||
*
|
||||
* @param aEventDispatcher is the object that will be used for dispatching events.
|
||||
*/
|
||||
void SetEventDispatcher( TOOL_DISPATCHER* aEventDispatcher );
|
||||
|
||||
void SetStatusBar( wxStatusBar* aStatusBar )
|
||||
{
|
||||
m_parentStatusBar = aStatusBar;
|
||||
}
|
||||
|
||||
void SetInfoBar( WX_INFOBAR* aInfoBar )
|
||||
{
|
||||
m_parentInfoBar = aInfoBar;
|
||||
}
|
||||
|
||||
void ReloadRequest( BOARD* aBoard = nullptr, S3D_CACHE* aCachePointer = nullptr );
|
||||
|
||||
/**
|
||||
* Query if there is a pending reload request.
|
||||
*
|
||||
* @return true if it wants to reload, false if there is no reload pending.
|
||||
*/
|
||||
bool IsReloadRequestPending() const
|
||||
{
|
||||
if( m_3d_render )
|
||||
return m_3d_render->IsReloadRequestPending();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current render ( a RENDER_3D_RAYTRACE* or a RENDER_3D_OPENGL* render )
|
||||
*/
|
||||
RENDER_3D_BASE* GetCurrentRender() const { return m_3d_render; }
|
||||
|
||||
/**
|
||||
* Request to render the current view in Raytracing mode.
|
||||
*/
|
||||
void RenderRaytracingRequest();
|
||||
|
||||
/**
|
||||
* Request a screenshot and output it to the \a aDstImage
|
||||
*
|
||||
* @param aDstImage - Screenshot destination image
|
||||
*/
|
||||
void GetScreenshot( wxImage& aDstImage );
|
||||
|
||||
/**
|
||||
* Helper function to call view commands.
|
||||
*
|
||||
* @param aKeycode ascii key commands.
|
||||
* @return true if the key code was handled, false if no command found for this code.
|
||||
*/
|
||||
bool SetView3D( int aKeycode );
|
||||
|
||||
/**
|
||||
* Enable or disable camera animation when switching to a pre-defined view.
|
||||
*/
|
||||
void SetAnimationEnabled( bool aEnable ) { m_animation_enabled = aEnable; }
|
||||
bool GetAnimationEnabled() const { return m_animation_enabled; }
|
||||
|
||||
/**
|
||||
* Set the camera animation moving speed multiplier option.
|
||||
*
|
||||
* @param aMultiplier one of the possible integer options: [1,2,3,4,5].
|
||||
*/
|
||||
void SetMovingSpeedMultiplier( int aMultiplier ) { m_moving_speed_multiplier = aMultiplier; }
|
||||
int GetMovingSpeedMultiplier() const { return m_moving_speed_multiplier; }
|
||||
|
||||
int GetProjectionMode() const { return (int) m_camera.GetProjection(); };
|
||||
void SetProjectionMode( int aMode ) { m_camera.SetProjection( (PROJECTION_TYPE) aMode ); }
|
||||
|
||||
/**
|
||||
* Notify that the render engine was changed.
|
||||
*/
|
||||
void RenderEngineChanged();
|
||||
|
||||
/**
|
||||
* Update the status bar with the position information.
|
||||
*/
|
||||
void DisplayStatus();
|
||||
|
||||
/**
|
||||
* Schedule a refresh update of the canvas.
|
||||
*
|
||||
* @param aRedrawImmediately true will request a redraw, false will schedule a redraw
|
||||
* after a short timeout.
|
||||
*/
|
||||
void Request_refresh( bool aRedrawImmediately = true );
|
||||
|
||||
/**
|
||||
* Used to forward events to the canvas from popups, etc.
|
||||
*/
|
||||
void OnEvent( wxEvent& aEvent );
|
||||
|
||||
/**
|
||||
* Get information used to display 3D board.
|
||||
*/
|
||||
const BOARD_ADAPTER& GetBoardAdapter() const { return m_boardAdapter; }
|
||||
|
||||
/**
|
||||
* Get a value indicating whether to render the pivot.
|
||||
*/
|
||||
bool GetRenderPivot() { return m_render_pivot; }
|
||||
|
||||
/**
|
||||
* Set aValue indicating whether to render the pivot.
|
||||
*
|
||||
* @param aValue true will cause the pivot to be rendered on the next redraw.
|
||||
*/
|
||||
void SetRenderPivot( bool aValue ) { m_render_pivot = aValue; }
|
||||
|
||||
/**
|
||||
* Get a value indicating whether to render the 3dmouse pivot.
|
||||
*/
|
||||
bool GetRender3dmousePivot()
|
||||
{
|
||||
return m_render3dmousePivot;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set aValue indicating whether to render the 3dmouse pivot.
|
||||
*
|
||||
* @param aValue true will cause the pivot to be rendered on the next redraw.
|
||||
*/
|
||||
void SetRender3dmousePivot( bool aValue )
|
||||
{
|
||||
m_render3dmousePivot = aValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the position of the the 3dmouse pivot.
|
||||
*
|
||||
* @param aPos is the position of the 3dmouse rotation pivot
|
||||
*/
|
||||
void Set3dmousePivotPos( const SFVEC3F& aPos )
|
||||
{
|
||||
m_3dmousePivotPos = aPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual function to repaint the canvas.
|
||||
*
|
||||
* It is usually called by OnPaint() but because it does not use a wxPaintDC it can be
|
||||
* called outside a wxPaintEvent
|
||||
*/
|
||||
void DoRePaint();
|
||||
|
||||
private:
|
||||
// The wxPaintEvent event. mainly calls DoRePaint()
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnRefreshRequest( wxEvent& aEvent );
|
||||
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
|
||||
void OnMagnify( wxMouseEvent& event );
|
||||
#endif
|
||||
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
void OnLeftDown( wxMouseEvent& event );
|
||||
void OnLeftUp( wxMouseEvent& event );
|
||||
void OnMiddleUp( wxMouseEvent& event );
|
||||
void OnMiddleDown( wxMouseEvent& event );
|
||||
void OnTimerTimeout_Editing( wxTimerEvent& event );
|
||||
void OnCloseWindow( wxCloseEvent& event );
|
||||
void OnResize( wxSizeEvent& event );
|
||||
void OnTimerTimeout_Redraw( wxTimerEvent& event );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
/**
|
||||
*Stop the editing time so it will not timeout.
|
||||
*/
|
||||
void stop_editingTimeOut_Timer();
|
||||
|
||||
/**
|
||||
* Reset the editing timer.
|
||||
*/
|
||||
void restart_editingTimeOut_Timer();
|
||||
|
||||
/**
|
||||
* Start a camera movement.
|
||||
*
|
||||
* @param aMovingSpeed the time speed.
|
||||
* @param aRenderPivot if it should display pivot cursor while move.
|
||||
*/
|
||||
void request_start_moving_camera( float aMovingSpeed = 2.0f, bool aRenderPivot = true );
|
||||
|
||||
/**
|
||||
* This function hits a ray to the board and start a movement.
|
||||
*/
|
||||
void move_pivot_based_on_cur_mouse_position();
|
||||
|
||||
/**
|
||||
* Render the pivot cursor.
|
||||
*
|
||||
* @param t time between 0.0 and 1.0.
|
||||
* @param aScale scale to apply on the cursor.
|
||||
*/
|
||||
void render_pivot( float t, float aScale );
|
||||
|
||||
/**
|
||||
* Render the 3dmouse pivot cursor.
|
||||
*
|
||||
* @param aScale scale to apply on the cursor.
|
||||
*/
|
||||
void render3dmousePivot( float aScale );
|
||||
|
||||
/**
|
||||
* @return true if OpenGL initialization succeeded.
|
||||
*/
|
||||
bool initializeOpenGL();
|
||||
|
||||
/**
|
||||
* Free created targets and openGL context.
|
||||
*/
|
||||
void releaseOpenGL();
|
||||
|
||||
RAY getRayAtCurrentMousePosition();
|
||||
|
||||
private:
|
||||
TOOL_DISPATCHER* m_eventDispatcher;
|
||||
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
|
||||
WX_INFOBAR* m_parentInfoBar;
|
||||
|
||||
wxGLContext* m_glRC; // Current OpenGL context
|
||||
bool m_is_opengl_initialized;
|
||||
bool m_is_opengl_version_supported;
|
||||
|
||||
wxTimer m_editing_timeout_timer; // Expires after some time signaling that
|
||||
// the mouse / keyboard movements are over
|
||||
wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event
|
||||
std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time
|
||||
|
||||
bool m_render_pivot; // Render the pivot while camera moving
|
||||
float m_camera_moving_speed; // 1.0f will be 1:1
|
||||
unsigned m_strtime_camera_movement; // Ticktime of camera movement start
|
||||
bool m_animation_enabled; // Camera animation enabled
|
||||
int m_moving_speed_multiplier; // Camera animation speed multiplier option
|
||||
|
||||
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
|
||||
RENDER_3D_BASE* m_3d_render;
|
||||
RENDER_3D_RAYTRACE* m_3d_render_raytracing;
|
||||
RENDER_3D_OPENGL* m_3d_render_opengl;
|
||||
|
||||
bool m_opengl_supports_raytracing;
|
||||
bool m_render_raytracing_was_requested;
|
||||
|
||||
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
|
||||
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
|
||||
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_CANVAS". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
|
||||
#endif // EDA_3D_CANVAS_H
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file eda_3d_canvas_pivot.cpp
|
||||
* @brief Implementation of a 3d cursor
|
||||
*/
|
||||
|
||||
#include "../common_ogl/openGL_includes.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "eda_3d_canvas.h"
|
||||
|
||||
|
||||
static void pivot_render_triangles( float t )
|
||||
{
|
||||
wxASSERT( t >= 0.0f );
|
||||
|
||||
SFVEC3F vertexPointer[12];
|
||||
|
||||
const float u = 1.0f / 6.0f;
|
||||
|
||||
vertexPointer[0] = SFVEC3F( ( -3.0f + t ) * u, -2.0f * u, 0.0f );
|
||||
vertexPointer[1] = SFVEC3F( ( -3.0f + t ) * u, 2.0f * u, 0.0f );
|
||||
vertexPointer[2] = SFVEC3F( ( -1.0f + t ) * u, 0.0f * u, 0.0f );
|
||||
|
||||
vertexPointer[3] = SFVEC3F( -2.0f * u, ( -3.0f + t ) * u, 0.0f );
|
||||
vertexPointer[4] = SFVEC3F( 2.0f * u, ( -3.0f + t ) * u, 0.0f );
|
||||
vertexPointer[5] = SFVEC3F( 0.0f * u, ( -1.0f + t ) * u, 0.0f );
|
||||
|
||||
vertexPointer[6] = SFVEC3F( ( 3.0f - t ) * u, -2.0f * u, 0.0f );
|
||||
vertexPointer[7] = SFVEC3F( ( 3.0f - t ) * u, 2.0f * u, 0.0f );
|
||||
vertexPointer[8] = SFVEC3F( ( 1.0f - t ) * u, 0.0f * u, 0.0f );
|
||||
|
||||
vertexPointer[9] = SFVEC3F( 2.0f * u, ( 3.0f - t ) * u, 0.0f );
|
||||
vertexPointer[10] = SFVEC3F( -2.0f * u, ( 3.0f - t ) * u, 0.0f );
|
||||
vertexPointer[11] = SFVEC3F( 0.0f * u, ( 1.0f - t ) * u, 0.0f );
|
||||
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
glDisableClientState( GL_NORMAL_ARRAY );
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glVertexPointer( 3, GL_FLOAT, 0, vertexPointer );
|
||||
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glDrawArrays( GL_TRIANGLES, 0, 4 * 3 );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::render_pivot( float t, float aScale )
|
||||
{
|
||||
wxASSERT( aScale >= 0.0f );
|
||||
wxASSERT( t >= 0.0f );
|
||||
|
||||
if( t > 1.0f )
|
||||
t = 1.0f;
|
||||
|
||||
const SFVEC3F &lookAtPos = m_camera.GetLookAtPos_T1();
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_CULL_FACE );
|
||||
|
||||
// Set projection and modelview matrixes
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
|
||||
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColor4f( 0.0f, 1.0f, 0.0f, 0.75f - t * 0.75f );
|
||||
|
||||
// Translate to the look at position
|
||||
glTranslatef( lookAtPos.x, lookAtPos.y, lookAtPos.z );
|
||||
|
||||
glScalef( aScale, aScale, aScale );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
|
||||
t = t * 0.80f;
|
||||
glScalef( 1.0f - t, 1.0f - t, 1.0f - t );
|
||||
glColor4f( 0.0f, 1.0f, 0.0f, 0.8f - t );
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef( t * 90.0f, 0.0f, 0.0f, 1.0f );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef( -t * 90.0f, 0.0f, 0.0f, 1.0f );
|
||||
pivot_render_triangles( t * 0.5f );
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::render3dmousePivot( float aScale )
|
||||
{
|
||||
wxASSERT( aScale >= 0.0f );
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_CULL_FACE );
|
||||
|
||||
// Set projection and modelview matrixes
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetProjectionMatrix() ) );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glLoadMatrixf( glm::value_ptr( m_camera.GetViewMatrix() ) );
|
||||
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColor4f( 0.0f, 0.667f, 0.902f, 0.75f );
|
||||
|
||||
// Translate to the look at position
|
||||
glTranslatef( m_3dmousePivotPos.x, m_3dmousePivotPos.y, m_3dmousePivotPos.z );
|
||||
|
||||
glPointSize( 16.0f );
|
||||
glEnable( GL_POINT_SMOOTH );
|
||||
glHint( GL_POINT_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glScalef( aScale, aScale, aScale );
|
||||
|
||||
// Draw a point at the look at position.
|
||||
glBegin( GL_POINTS );
|
||||
glVertex3f( 0, 0, 0 );
|
||||
glEnd();
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDisable( GL_POINT_SMOOTH );
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file 3d_class.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
|
||||
S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
|
||||
EDA_ITEM( father, NOT_USED )
|
||||
{
|
||||
m_DiffuseColor.x = m_DiffuseColor.y = m_DiffuseColor.z = 1.0;
|
||||
m_SpecularColor.x = m_SpecularColor.y = m_SpecularColor.z = 1.0;
|
||||
m_AmbientIntensity = 1.0;
|
||||
m_Transparency = 0.0;
|
||||
m_Shininess = 1.0;
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MATERIAL::SetMaterial()
|
||||
{
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
glColor4f( m_DiffuseColor.x * m_AmbientIntensity,
|
||||
m_DiffuseColor.y * m_AmbientIntensity,
|
||||
m_DiffuseColor.z * m_AmbientIntensity,
|
||||
1.0 - m_Transparency );
|
||||
#if 0
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_SPECULAR );
|
||||
glColor3f( m_SpecularColor.x, m_SpecularColor.y, m_SpecularColor.z );
|
||||
#endif
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::Copy( S3D_MASTER* pattern )
|
||||
{
|
||||
SetShape3DName( pattern->GetShape3DName() );
|
||||
m_MatScale = pattern->m_MatScale;
|
||||
m_MatRotation = pattern->m_MatRotation;
|
||||
m_MatPosition = pattern->m_MatPosition;
|
||||
m_3D_Drawings = NULL;
|
||||
m_Materials = NULL;
|
||||
}
|
||||
|
||||
|
||||
S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( aParent, NOT_USED )
|
||||
{
|
||||
m_MatScale.x = m_MatScale.y = m_MatScale.z = 1.0;
|
||||
m_3D_Drawings = NULL;
|
||||
m_Materials = NULL;
|
||||
m_ShapeType = FILE3D_NONE;
|
||||
}
|
||||
|
||||
|
||||
S3D_MASTER:: ~S3D_MASTER()
|
||||
{
|
||||
STRUCT_3D_SHAPE* next;
|
||||
S3D_MATERIAL* nextmat;
|
||||
|
||||
for( ; m_3D_Drawings != NULL; m_3D_Drawings = next )
|
||||
{
|
||||
next = m_3D_Drawings->Next();
|
||||
delete m_3D_Drawings;
|
||||
}
|
||||
|
||||
for( ; m_Materials != NULL; m_Materials = nextmat )
|
||||
{
|
||||
nextmat = m_Materials->Next();
|
||||
delete m_Materials;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool S3D_MASTER::Is3DType( enum FILE3D_TYPE aShapeType )
|
||||
{
|
||||
// type 'none' is not valid and will always return false
|
||||
if( aShapeType == FILE3D_NONE )
|
||||
return false;
|
||||
|
||||
// no one is interested if we have no file
|
||||
if( m_Shape3DName.empty() )
|
||||
return false;
|
||||
|
||||
if( aShapeType == m_ShapeType )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::SetShape3DName( const wxString& aShapeName )
|
||||
{
|
||||
m_ShapeType = FILE3D_NONE;
|
||||
m_Shape3DName = aShapeName;
|
||||
|
||||
if( m_Shape3DName.empty() )
|
||||
return;
|
||||
|
||||
wxFileName fn = m_Shape3DName;
|
||||
wxString ext = fn.GetExt();
|
||||
|
||||
if( ext == wxT( "wrl" ) || ext == wxT( "x3d" ) )
|
||||
m_ShapeType = FILE3D_VRML;
|
||||
else if( ext == wxT( "idf" ) )
|
||||
m_ShapeType = FILE3D_IDF;
|
||||
else
|
||||
m_ShapeType = FILE3D_UNKNOWN;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STRUCT_3D_SHAPE::STRUCT_3D_SHAPE( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( aParent, NOT_USED )
|
||||
{
|
||||
m_3D_Coord = NULL;
|
||||
m_3D_CoordIndex = NULL;
|
||||
m_3D_Points = 0;
|
||||
}
|
||||
|
||||
|
||||
STRUCT_3D_SHAPE:: ~STRUCT_3D_SHAPE()
|
||||
{
|
||||
delete m_3D_Coord;
|
||||
delete m_3D_CoordIndex;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_basic_functions.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <trigo.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <3d_draw_basic_functions.h>
|
||||
|
||||
// Imported function:
|
||||
extern void Set_Object_Data( std::vector<S3D_VERTEX>& aVertices, double aBiuTo3DUnits );
|
||||
extern void CheckGLError();
|
||||
|
||||
// Number of segments to approximate a circle by segments
|
||||
#define SEGM_PER_CIRCLE 16
|
||||
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK
|
||||
#endif
|
||||
|
||||
// CALLBACK functions for GLU_TESS
|
||||
static void CALLBACK tessBeginCB( GLenum which );
|
||||
static void CALLBACK tessEndCB();
|
||||
static void CALLBACK tessErrorCB( GLenum errorCode );
|
||||
static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
|
||||
|
||||
// 2 helper functions to set the current normal vector for gle items
|
||||
static inline void SetNormalZpos()
|
||||
{
|
||||
glNormal3f( 0.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
static inline void SetNormalZneg()
|
||||
{
|
||||
glNormal3f( 0.0, 0.0, -1.0 );
|
||||
}
|
||||
|
||||
|
||||
/* Draw3D_VerticalPolygonalCylinder is a helper function.
|
||||
*
|
||||
* draws a "vertical cylinder" having a polygon shape
|
||||
* from Z position = aZpos to aZpos + aHeight
|
||||
* Used to create the vertical sides of 3D horizontal shapes with thickness.
|
||||
*/
|
||||
static void Draw3D_VerticalPolygonalCylinder( const CPOLYGONS_LIST& aPolysList,
|
||||
int aHeight, int aZpos,
|
||||
bool aInside, double aBiuTo3DUnits )
|
||||
{
|
||||
if( aHeight == 0 )
|
||||
return;
|
||||
|
||||
std::vector<S3D_VERTEX> coords;
|
||||
coords.resize( 4 );
|
||||
|
||||
// Init Z position of the 4 points of a GL_QUAD
|
||||
if( aInside )
|
||||
{
|
||||
coords[0].z = aZpos;
|
||||
coords[1].z = aZpos + aHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
coords[0].z = aZpos + aHeight;
|
||||
coords[1].z = aZpos;
|
||||
}
|
||||
coords[2].z = coords[1].z;
|
||||
coords[3].z = coords[0].z;
|
||||
|
||||
// Draw the vertical polygonal side
|
||||
int startContour = 0;
|
||||
for( unsigned ii = 0; ii < aPolysList.GetCornersCount(); ii++ )
|
||||
{
|
||||
unsigned jj = ii + 1;
|
||||
|
||||
if( aPolysList.IsEndContour( ii ) || jj >= aPolysList.GetCornersCount() )
|
||||
{
|
||||
jj = startContour;
|
||||
startContour = ii + 1;
|
||||
}
|
||||
|
||||
// Build the 4 vertices of each GL_QUAD
|
||||
coords[0].x = aPolysList.GetX( ii );
|
||||
coords[0].y = -aPolysList.GetY( ii );
|
||||
coords[1].x = coords[0].x;
|
||||
coords[1].y = coords[0].y; // only z change
|
||||
coords[2].x = aPolysList.GetX( jj );
|
||||
coords[2].y = -aPolysList.GetY( jj );
|
||||
coords[3].x = coords[2].x;
|
||||
coords[3].y = coords[2].y; // only z change
|
||||
|
||||
// Creates the GL_QUAD
|
||||
Set_Object_Data( coords, aBiuTo3DUnits );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetGLColor( EDA_COLOR_T color, double alpha )
|
||||
{
|
||||
double red, green, blue;
|
||||
const StructColors &colordata = g_ColorRefs[ColorGetBase( color )];
|
||||
|
||||
red = colordata.m_Red / 255.0;
|
||||
blue = colordata.m_Blue / 255.0;
|
||||
green = colordata.m_Green / 255.0;
|
||||
glColor4f( red, green, blue, alpha );
|
||||
}
|
||||
|
||||
|
||||
/* draw all solid polygons found in aPolysList
|
||||
* aZpos = z position in board internal units
|
||||
* aThickness = thickness in board internal units
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
|
||||
int aZpos, int aThickness, double aBiuTo3DUnits )
|
||||
{
|
||||
GLUtesselator* tess = gluNewTess();
|
||||
|
||||
gluTessCallback( tess, GLU_TESS_BEGIN, ( void (CALLBACK*) () )tessBeginCB );
|
||||
gluTessCallback( tess, GLU_TESS_END, ( void (CALLBACK*) () )tessEndCB );
|
||||
gluTessCallback( tess, GLU_TESS_ERROR, ( void (CALLBACK*) () )tessErrorCB );
|
||||
gluTessCallback( tess, GLU_TESS_VERTEX, ( void (CALLBACK*) () )tessCPolyPt2Vertex );
|
||||
|
||||
GLdouble v_data[3];
|
||||
double zpos = ( aZpos + (aThickness / 2) ) * aBiuTo3DUnits;
|
||||
g_Parm_3D_Visu.m_CurrentZpos = zpos;
|
||||
v_data[2] = aZpos + (aThickness / 2);
|
||||
|
||||
// Set normal to toward positive Z axis, for a solid object only (to draw the top side)
|
||||
if( aThickness )
|
||||
SetNormalZpos();
|
||||
|
||||
// gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
|
||||
|
||||
// Draw solid areas contained in this list
|
||||
CPOLYGONS_LIST polylist = aPolysList; // temporary copy for gluTessVertex
|
||||
|
||||
for( int side = 0; side < 2; side++ )
|
||||
{
|
||||
int startContour = 1;
|
||||
|
||||
for( unsigned ii = 0; ii < polylist.GetCornersCount(); ii++ )
|
||||
{
|
||||
if( startContour == 1 )
|
||||
{
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
gluTessBeginContour( tess );
|
||||
startContour = 0;
|
||||
}
|
||||
|
||||
v_data[0] = polylist.GetX( ii ) * aBiuTo3DUnits;
|
||||
v_data[1] = -polylist.GetY( ii ) * aBiuTo3DUnits;
|
||||
// gluTessVertex store pointers on data, not data, so do not store
|
||||
// different corners values in a temporary variable
|
||||
// but send pointer on each CPolyPt value in polylist
|
||||
// before calling gluDeleteTess
|
||||
gluTessVertex( tess, v_data, &polylist[ii] );
|
||||
|
||||
if( polylist.IsEndContour( ii ) )
|
||||
{
|
||||
gluTessEndContour( tess );
|
||||
gluTessEndPolygon( tess );
|
||||
startContour = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( aThickness == 0 )
|
||||
break;
|
||||
|
||||
// Prepare the bottom side of solid areas
|
||||
zpos = ( aZpos - (aThickness / 2) ) * aBiuTo3DUnits;
|
||||
g_Parm_3D_Visu.m_CurrentZpos = zpos;
|
||||
v_data[2] = zpos;
|
||||
// Now;, set normal to toward negative Z axis, for the solid object bottom side
|
||||
SetNormalZneg();
|
||||
}
|
||||
|
||||
gluDeleteTess( tess );
|
||||
|
||||
if( aThickness == 0 )
|
||||
return;
|
||||
|
||||
// Build the 3D data : vertical side
|
||||
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2), false, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
/* draw the solid polygon found in aPolysList
|
||||
* The first polygon is the main polygon, others are holes
|
||||
* See Draw3D_SolidHorizontalPolyPolygons for more info
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolygonWithHoles( const CPOLYGONS_LIST& aPolysList,
|
||||
int aZpos, int aThickness,
|
||||
double aBiuTo3DUnits )
|
||||
{
|
||||
CPOLYGONS_LIST polygon;
|
||||
|
||||
ConvertPolysListWithHolesToOnePolygon( aPolysList, polygon );
|
||||
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, aThickness, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
/* draw a cylinder (a tube) using 3D primitives.
|
||||
* the cylinder axis is parallel to the Z axis
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
|
||||
int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
CPOLYGONS_LIST outer_cornerBuffer;
|
||||
|
||||
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
|
||||
aRadius + (aThickness / 2), slice );
|
||||
|
||||
std::vector<S3D_VERTEX> coords;
|
||||
coords.resize( 4 );
|
||||
|
||||
CPOLYGONS_LIST inner_cornerBuffer;
|
||||
if( aThickness ) // build the the vertical inner polygon (hole)
|
||||
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
|
||||
aRadius - (aThickness / 2), slice );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
// Draw the vertical outer side
|
||||
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
|
||||
aHeight, aZpos, false, aBiuTo3DUnits );
|
||||
if( aThickness )
|
||||
// Draws the vertical inner side (hole)
|
||||
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
|
||||
aHeight, aZpos, true, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
if( aThickness )
|
||||
{
|
||||
// draw top (front) and bottom (back) horizontal sides (rings)
|
||||
SetNormalZpos();
|
||||
outer_cornerBuffer.Append( inner_cornerBuffer );
|
||||
CPOLYGONS_LIST polygon;
|
||||
|
||||
ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );
|
||||
// draw top (front) horizontal ring
|
||||
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
// draw bottom (back) horizontal ring
|
||||
SetNormalZneg();
|
||||
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, 0, aBiuTo3DUnits );
|
||||
}
|
||||
}
|
||||
|
||||
SetNormalZpos();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function Draw3D_ZaxisOblongCylinder:
|
||||
* draw a segment with an oblong hole.
|
||||
* Used to draw oblong holes
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
|
||||
int aRadius, int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
// Build the points to approximate oblong cylinder by segments
|
||||
CPOLYGONS_LIST outer_cornerBuffer;
|
||||
|
||||
int segm_width = (aRadius * 2) + aThickness;
|
||||
TransformRoundedEndsSegmentToPolygon( outer_cornerBuffer, aAxis1Pos,
|
||||
aAxis2Pos, slice, segm_width );
|
||||
|
||||
// Draw the oblong outer cylinder
|
||||
if( aHeight )
|
||||
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer, aHeight, aZpos,
|
||||
false, aBiuTo3DUnits );
|
||||
|
||||
if( aThickness )
|
||||
{
|
||||
CPOLYGONS_LIST inner_cornerBuffer;
|
||||
segm_width = aRadius * 2;
|
||||
TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
|
||||
aAxis2Pos, slice, segm_width );
|
||||
|
||||
// Draw the oblong inner cylinder
|
||||
if( aHeight )
|
||||
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer, aHeight,
|
||||
aZpos, true, aBiuTo3DUnits );
|
||||
|
||||
// Build the horizontal full polygon shape
|
||||
// (outer polygon shape - inner polygon shape)
|
||||
outer_cornerBuffer.Append( inner_cornerBuffer );
|
||||
|
||||
CPOLYGONS_LIST polygon;
|
||||
ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );
|
||||
|
||||
// draw top (front) horizontal side (ring)
|
||||
SetNormalZpos();
|
||||
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits );
|
||||
|
||||
if( aHeight )
|
||||
{
|
||||
// draw bottom (back) horizontal side (ring)
|
||||
SetNormalZneg();
|
||||
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, 0, aBiuTo3DUnits );
|
||||
}
|
||||
}
|
||||
|
||||
SetNormalZpos();
|
||||
}
|
||||
|
||||
|
||||
/* draw a thick segment using 3D primitives, in a XY plane
|
||||
* wxPoint aStart, wxPoint aEnd = YX position of end in board units
|
||||
* aWidth = width of segment in board units
|
||||
* aThickness = thickness of segment in board units
|
||||
* aZpos = z position of segment in board units
|
||||
*/
|
||||
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
|
||||
int aWidth, int aThickness, int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
CPOLYGONS_LIST cornerBuffer;
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
|
||||
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
|
||||
double aArcAngle, int aWidth, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits )
|
||||
{
|
||||
const int slice = SEGM_PER_CIRCLE;
|
||||
|
||||
CPOLYGONS_LIST cornerBuffer;
|
||||
TransformArcToPolygon( cornerBuffer, aCenterPos, aStartPoint, aArcAngle,
|
||||
slice, aWidth );
|
||||
|
||||
Draw3D_SolidHorizontalPolyPolygons( cornerBuffer, aZpos, aThickness, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
// GLU_TESS CALLBACKS
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CALLBACK tessBeginCB( GLenum which )
|
||||
{
|
||||
glBegin( which );
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessEndCB()
|
||||
{
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
|
||||
{
|
||||
// cast back to double type
|
||||
const CPolyPt* ptr = (const CPolyPt*) data;
|
||||
|
||||
glVertex3d( ptr->x * g_Parm_3D_Visu.m_BiuTo3Dunits,
|
||||
-ptr->y * g_Parm_3D_Visu.m_BiuTo3Dunits,
|
||||
g_Parm_3D_Visu.m_CurrentZpos );
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK tessErrorCB( GLenum errorCode )
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
const GLubyte* errorStr;
|
||||
|
||||
errorStr = gluErrorString( errorCode );
|
||||
|
||||
// DEBUG //
|
||||
DBG( printf( "Tess ERROR: %s\n", errorStr ); )
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_draw_basic_functions.h
|
||||
*/
|
||||
#ifndef _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
#define _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
|
||||
// angle increment to draw a circle, approximated by segments
|
||||
#define ANGLE_INC( x ) ( 3600 / (x) )
|
||||
|
||||
/** draw all solid polygons found in aPolysList
|
||||
* @param aPolysList = the poligon list to draw
|
||||
* @param aZpos = z position in board internal units
|
||||
* @param aThickness = thickness in board internal units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
|
||||
int aZpos, int aThickness, double aBiuTo3DUnits );
|
||||
|
||||
/** draw the solid polygon found in aPolysList
|
||||
* The first polygonj is the main polygon, others are holes
|
||||
* @param aPolysList = the polygon with holes to draw
|
||||
* @param aZpos = z position in board internal units
|
||||
* @param aThickness = thickness in board internal units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidHorizontalPolygonWithHoles( const CPOLYGONS_LIST& aPolysList,
|
||||
int aZpos, int aThickness, double aBiuTo3DUnits );
|
||||
|
||||
/** draw a thick segment using 3D primitives, in a XY plane
|
||||
* @param aStart = YX position of start point in board units
|
||||
* @param aEnd = YX position of end point in board units
|
||||
* @param aWidth = width of segment in board units
|
||||
* @param aThickness = thickness of segment in board units
|
||||
* @param aZpos = z position of segment in board units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
* If aThickness = 0, a polygon area is drawn in a XY plane at Z position = aZpos.
|
||||
* If aThickness > 0, a solid object is drawn.
|
||||
* The top side is located at aZpos + aThickness / 2
|
||||
* The bottom side is located at aZpos - aThickness / 2
|
||||
*/
|
||||
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
|
||||
int aWidth, int aThickness, int aZpos,
|
||||
double aBiuTo3DUnits );
|
||||
|
||||
/** draw an arc using 3D primitives, in a XY plane
|
||||
* @param aCenterPos = XY position of the center in board units
|
||||
* @param aStartPoint = start point coordinate of arc in board units
|
||||
* @param aWidth = width of the circle in board units
|
||||
* @param aArcAngle = arc angle in 1/10 degrees
|
||||
* @param aWidth = thickness of arc
|
||||
* @param aThickness = thickness of segment in board units
|
||||
* @param aZpos = z position of segment in board units
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*/
|
||||
void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
|
||||
double aArcAngle, int aWidth, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
|
||||
|
||||
/** draw a thick cylinder (a tube) using 3D primitives.
|
||||
* the cylinder axis is parallel to the Z axis
|
||||
* @param aCenterPos = XY position of the axis cylinder ( board internal units)
|
||||
* @param aRadius = radius of the cylinder ( board internal units)
|
||||
* @param aHeight = height of the cylinder ( boardinternal units)
|
||||
* @param aThickness = tichkness of tube ( boardinternal units)
|
||||
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units)
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*
|
||||
* If aHeight = height of the cylinder is 0, only one ring will be drawn
|
||||
* If aThickness = 0, only one cylinder (not a tube) will be drawn
|
||||
*/
|
||||
void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
|
||||
int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
|
||||
/** draw an oblong cylinder (oblong tube) using 3D primitives.
|
||||
* the cylinder axis are parallel to the Z axis
|
||||
* @param aAxis1Pos = position of the first axis cylinder
|
||||
* @param aAxis2Pos = position of the second axis cylinder
|
||||
* @param aRadius = radius of the cylinder ( board internal units )
|
||||
* @param aHeight = height of the cylinder ( board internal units )
|
||||
* @param aThickness = tichkness of tube ( board internal units )
|
||||
* @param aZpos = Z position of the bottom side of the cylinder ( board internal units )
|
||||
* @param aBiuTo3DUnits = board internal units to 3D units scaling value
|
||||
*/
|
||||
void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
|
||||
int aRadius, int aHeight, int aThickness,
|
||||
int aZpos, double aBiuTo3DUnits );
|
||||
/**
|
||||
* Set the current 3D color from a Kicad color, with optional transparency
|
||||
* @param aColor = a EDA_COLOR_T kicad color index
|
||||
* @param aTransparency = the color transparency (default = 1.0 = no transparency)
|
||||
*/
|
||||
void SetGLColor( EDA_COLOR_T aColor, double aTransparency = 1.0 );
|
||||
|
||||
|
||||
#endif // _3D_DRAW_BASIC_FUNCTIONS_H_
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_enums.h
|
||||
* @brief declared enumerations and flags
|
||||
*/
|
||||
|
||||
#ifndef _3D_ENUMS_H_
|
||||
#define _3D_ENUMS_H_
|
||||
|
||||
/// Rotation direction for the 3d canvas
|
||||
enum class ROTATION_DIR
|
||||
{
|
||||
X_CW,
|
||||
X_CCW,
|
||||
Y_CW,
|
||||
Y_CCW,
|
||||
Z_CW,
|
||||
Z_CCW
|
||||
};
|
||||
|
||||
/// Camera types
|
||||
enum class CAMERA_TYPE
|
||||
{
|
||||
TRACKBALL
|
||||
};
|
||||
|
||||
// Do not modify the following enum numbers, they are saved in the config file and used in the UI
|
||||
|
||||
/// Grid types
|
||||
enum class GRID3D_TYPE
|
||||
{
|
||||
NONE = 0,
|
||||
GRID_1MM = 1,
|
||||
GRID_2P5MM = 2,
|
||||
GRID_5MM = 3,
|
||||
GRID_10MM = 4
|
||||
};
|
||||
|
||||
/// Render engine mode
|
||||
enum class RENDER_ENGINE
|
||||
{
|
||||
OPENGL = 0,
|
||||
RAYTRACING = 1,
|
||||
};
|
||||
|
||||
/// Render 3d model shape materials mode
|
||||
enum class MATERIAL_MODE
|
||||
{
|
||||
NORMAL = 0, ///< Use all material properties from model file
|
||||
DIFFUSE_ONLY = 1, ///< Use only diffuse material properties
|
||||
CAD_MODE = 2 ///< Use a gray shading based on diffuse material
|
||||
};
|
||||
|
||||
#endif // _3D_ENUMS_H_
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_fastmath.cpp
|
||||
* @brief
|
||||
*/
|
||||
|
||||
|
||||
#include "3d_fastmath.h"
|
||||
|
||||
|
||||
// Fast Float Random Numbers
|
||||
// a small and fast implementation for random float numbers in the range [-1,1]
|
||||
// References : Posted by dominik.ries[AT]gmail[DOT]com
|
||||
// http://www.musicdsp.org/showone.php?id=273
|
||||
|
||||
|
||||
// set the initial seed to whatever you like
|
||||
static int s_randSeed = 1;
|
||||
|
||||
// fast rand float, using full 32bit precision
|
||||
// returns in the range [-1, 1] (not confirmed)
|
||||
float Fast_RandFloat()
|
||||
{
|
||||
s_randSeed *= 16807;
|
||||
|
||||
return (float)s_randSeed * 4.6566129e-010f;
|
||||
}
|
||||
|
||||
|
||||
// Fast rand, as described here:
|
||||
// http://wiki.osdev.org/Random_Number_Generator
|
||||
|
||||
static unsigned long int s_nextRandSeed = 1;
|
||||
|
||||
int Fast_rand( void ) // RAND_MAX assumed to be 32767
|
||||
{
|
||||
s_nextRandSeed = s_nextRandSeed * 1103515245 + 12345;
|
||||
|
||||
return (unsigned int)(s_nextRandSeed >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
void Fast_srand( unsigned int seed )
|
||||
{
|
||||
s_nextRandSeed = seed;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_fastmath.h
|
||||
* @brief Defines math related functions
|
||||
*/
|
||||
|
||||
#ifndef _3D_FASTMATH_H
|
||||
#define _3D_FASTMATH_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Define this flag to use fast math optimizations
|
||||
#define FASTMATH_USE
|
||||
|
||||
#define L1_CACHE_LINE_SIZE 64
|
||||
|
||||
#ifdef FASTMATH_USE
|
||||
#define INTFLOORF(s) (lrintf( (s) - (0.5f - FLT_EPSILON) ))
|
||||
#else
|
||||
#define INTFLOORF(s) ((int)( floor(s) ))
|
||||
#endif
|
||||
|
||||
|
||||
// Fast Float Random Numbers
|
||||
// a small and fast implementation for random float numbers in the range [-1,1]
|
||||
// This is not thread safe
|
||||
float Fast_RandFloat();
|
||||
|
||||
int Fast_rand( void );
|
||||
void Fast_srand( unsigned int seed );
|
||||
|
||||
/**
|
||||
* This part contains some functions from the PBRT 3 source code.
|
||||
* https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h
|
||||
*/
|
||||
|
||||
/*
|
||||
pbrt source code is Copyright(c) 1998-2015
|
||||
Matt Pharr, Greg Humphreys, and Wenzel Jakob.
|
||||
|
||||
This file is part of pbrt.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Global Inline Functions
|
||||
inline uint32_t FloatToBits( float f )
|
||||
{
|
||||
uint32_t ui;
|
||||
|
||||
memcpy( &ui, &f, sizeof( float ) );
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
|
||||
inline float BitsToFloat( uint32_t ui )
|
||||
{
|
||||
float f;
|
||||
|
||||
memcpy( &f, &ui, sizeof (uint32_t ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t FloatToBits( double f )
|
||||
{
|
||||
uint64_t ui;
|
||||
|
||||
memcpy( &ui, &f, sizeof( double ) );
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
|
||||
inline double BitsToFloat( uint64_t ui )
|
||||
{
|
||||
double f;
|
||||
|
||||
memcpy( &f, &ui, sizeof( uint64_t ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
inline float NextFloatUp( float v )
|
||||
{
|
||||
// Handle infinity and negative zero for _NextFloatUp()_
|
||||
if( std::isinf( v ) && (v > 0.) )
|
||||
return v;
|
||||
|
||||
if( v == -0.f )
|
||||
v = 0.f;
|
||||
|
||||
// Advance _v_ to next higher float
|
||||
uint32_t ui = FloatToBits( v );
|
||||
|
||||
if( v >= 0. )
|
||||
++ui;
|
||||
else
|
||||
--ui;
|
||||
|
||||
return BitsToFloat( ui );
|
||||
}
|
||||
|
||||
|
||||
inline float NextFloatDown( float v )
|
||||
{
|
||||
// Handle infinity and positive zero for _NextFloatDown()_
|
||||
if( std::isinf( v ) && (v < 0.) )
|
||||
return v;
|
||||
|
||||
if( v == 0.f )
|
||||
v = -0.f;
|
||||
|
||||
uint32_t ui = FloatToBits( v );
|
||||
|
||||
if( v > 0. )
|
||||
--ui;
|
||||
else
|
||||
++ui;
|
||||
|
||||
return BitsToFloat( ui );
|
||||
}
|
||||
|
||||
#endif // 3D_FASTMATH_H
|
||||
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* @file 3d_frame.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <appl_wxstruct.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <3d_canvas.h>
|
||||
#include <info3d_visu.h>
|
||||
#include <trackball.h>
|
||||
|
||||
#include <wx/colordlg.h>
|
||||
#include <3d_viewer_id.h>
|
||||
#include <wxBasePcbFrame.h>
|
||||
|
||||
INFO3D_VISU g_Parm_3D_Visu;
|
||||
|
||||
// Key to store 3D Viewer config:
|
||||
static const wxString keyBgColor_Red( wxT( "BgColor_Red" ) );
|
||||
static const wxString keyBgColor_Green( wxT( "BgColor_Green" ) );
|
||||
static const wxString keyBgColor_Blue( wxT( "BgColor_Blue" ) );
|
||||
static const wxString keyShowRealisticMode( wxT( "ShowRealisticMode" ) );
|
||||
static const wxString keyShowAxis( wxT( "ShowAxis" ) );
|
||||
static const wxString keyShowZones( wxT( "ShowZones" ) );
|
||||
static const wxString keyShowFootprints( wxT( "ShowFootprints" ) );
|
||||
static const wxString keyShowCopperThickness( wxT( "ShowCopperThickness" ) );
|
||||
static const wxString keyShowAdhesiveLayers( wxT( "ShowAdhesiveLayers" ) );
|
||||
static const wxString keyShowSilkScreenLayers( wxT( "ShowSilkScreenLayers" ) );
|
||||
static const wxString keyShowSolderMaskLayers( wxT( "ShowSolderMasLayers" ) );
|
||||
static const wxString keyShowSolderPasteLayers( wxT( "ShowSolderPasteLayers" ) );
|
||||
static const wxString keyShowCommentsLayer( wxT( "ShowCommentsLayers" ) );
|
||||
static const wxString keyShowBoardBody( wxT( "ShowBoardBody" ) );
|
||||
static const wxString keyShowEcoLayers( wxT( "ShowEcoLayers" ) );
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_FRAME, EDA_BASE_FRAME )
|
||||
EVT_ACTIVATE( EDA_3D_FRAME::OnActivate )
|
||||
|
||||
EVT_TOOL_RANGE( ID_ZOOM_IN, ID_ZOOM_PAGE, EDA_3D_FRAME::Process_Zoom )
|
||||
EVT_TOOL_RANGE( ID_START_COMMAND_3D, ID_END_COMMAND_3D,
|
||||
EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_TOOL( ID_TOOL_SET_VISIBLE_ITEMS, EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( wxID_EXIT, EDA_3D_FRAME::Exit3DFrame )
|
||||
EVT_MENU( ID_MENU_SCREENCOPY_PNG, EDA_3D_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( ID_MENU_SCREENCOPY_JPEG, EDA_3D_FRAME::Process_Special_Functions )
|
||||
|
||||
EVT_MENU_RANGE( ID_MENU3D_GRID, ID_MENU3D_GRID_END,
|
||||
EDA_3D_FRAME::On3DGridSelection )
|
||||
|
||||
EVT_CLOSE( EDA_3D_FRAME::OnCloseWindow )
|
||||
|
||||
END_EVENT_TABLE() EDA_3D_FRAME::EDA_3D_FRAME( PCB_BASE_FRAME* parent,
|
||||
const wxString& title,
|
||||
long style ) :
|
||||
EDA_BASE_FRAME( parent, DISPLAY3D_FRAME_TYPE, title,
|
||||
wxDefaultPosition, wxDefaultSize, style, wxT( "Frame3D" ) )
|
||||
{
|
||||
m_canvas = NULL;
|
||||
m_reloadRequest = false;
|
||||
m_ortho = false;
|
||||
|
||||
// Give it an icon
|
||||
wxIcon icon;
|
||||
icon.CopyFromBitmap( KiBitmap( icon_3d_xpm ) );
|
||||
SetIcon( icon );
|
||||
|
||||
GetSettings();
|
||||
SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
|
||||
|
||||
// Create the status line
|
||||
static const int dims[5] = { -1, 100, 100, 100, 140 };
|
||||
|
||||
CreateStatusBar( 5 );
|
||||
SetStatusWidths( 5, dims );
|
||||
|
||||
CreateMenuBar();
|
||||
ReCreateMainToolbar();
|
||||
|
||||
// Make a EDA_3D_CANVAS
|
||||
int attrs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 };
|
||||
m_canvas = new EDA_3D_CANVAS( this, attrs );
|
||||
|
||||
m_auimgr.SetManagedWindow( this );
|
||||
|
||||
|
||||
EDA_PANEINFO horiztb;
|
||||
horiztb.HorizontalToolbarPane();
|
||||
|
||||
m_auimgr.AddPane( m_mainToolBar,
|
||||
wxAuiPaneInfo( horiztb ).Name( wxT( "m_mainToolBar" ) ).Top() );
|
||||
|
||||
m_auimgr.AddPane( m_canvas,
|
||||
wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() );
|
||||
|
||||
m_auimgr.Update();
|
||||
|
||||
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
|
||||
// in order to receive mouse events. Otherwise, the user has to click somewhere on
|
||||
// the canvas before it will respond to mouse wheel events.
|
||||
m_canvas->SetFocus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::Exit3DFrame( wxCommandEvent& event )
|
||||
{
|
||||
Close( true );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event )
|
||||
{
|
||||
if( Parent() )
|
||||
Parent()->m_Draw3DFrame = NULL;
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::GetSettings()
|
||||
{
|
||||
wxConfig* config = wxGetApp().GetSettings(); // Current config used by application
|
||||
class INFO3D_VISU& prms = g_Parm_3D_Visu;
|
||||
|
||||
if( config )
|
||||
{
|
||||
EDA_BASE_FRAME::LoadSettings();
|
||||
|
||||
config->Read( keyBgColor_Red, &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 );
|
||||
config->Read( keyBgColor_Green, &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 );
|
||||
config->Read( keyBgColor_Blue, &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 );
|
||||
|
||||
bool tmp;
|
||||
config->Read( keyShowRealisticMode, &tmp, false );
|
||||
prms.SetFlag( FL_USE_REALISTIC_MODE, tmp );
|
||||
|
||||
config->Read( keyShowAxis, &tmp, true );
|
||||
prms.SetFlag( FL_AXIS, tmp );
|
||||
|
||||
config->Read( keyShowFootprints, &tmp, true );
|
||||
prms.SetFlag( FL_MODULE, tmp );
|
||||
|
||||
config->Read( keyShowCopperThickness, &tmp, false );
|
||||
prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp );
|
||||
|
||||
config->Read( keyShowZones, &tmp, true );
|
||||
prms.SetFlag( FL_ZONE, tmp );
|
||||
|
||||
config->Read( keyShowAdhesiveLayers, &tmp, true );
|
||||
prms.SetFlag( FL_ADHESIVE, tmp );
|
||||
|
||||
config->Read( keyShowSilkScreenLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SILKSCREEN, tmp );
|
||||
|
||||
config->Read( keyShowSolderMaskLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SOLDERMASK, tmp );
|
||||
|
||||
config->Read( keyShowSolderPasteLayers, &tmp, true );
|
||||
prms.SetFlag( FL_SOLDERPASTE, tmp );
|
||||
|
||||
config->Read( keyShowCommentsLayer, &tmp, true );
|
||||
prms.SetFlag( FL_COMMENTS, tmp );
|
||||
|
||||
config->Read( keyShowEcoLayers, &tmp, true );
|
||||
prms.SetFlag( FL_ECO, tmp );
|
||||
|
||||
config->Read( keyShowBoardBody, &tmp, true );
|
||||
prms.SetFlag( FL_SHOW_BOARD_BODY, tmp );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::SaveSettings()
|
||||
{
|
||||
wxConfig* config = wxGetApp().GetSettings(); // Current config used by application
|
||||
|
||||
if( !config )
|
||||
return;
|
||||
|
||||
EDA_BASE_FRAME::SaveSettings();
|
||||
|
||||
config->Write( keyBgColor_Red, g_Parm_3D_Visu.m_BgColor.m_Red );
|
||||
config->Write( keyBgColor_Green, g_Parm_3D_Visu.m_BgColor.m_Green );
|
||||
config->Write( keyBgColor_Blue, g_Parm_3D_Visu.m_BgColor.m_Blue );
|
||||
class INFO3D_VISU& prms = g_Parm_3D_Visu;
|
||||
config->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) );
|
||||
config->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) );
|
||||
config->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) );
|
||||
config->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) );
|
||||
config->Write( keyShowZones, prms.GetFlag( FL_ZONE ) );
|
||||
config->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) );
|
||||
config->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) );
|
||||
config->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) );
|
||||
config->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) );
|
||||
config->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) );
|
||||
config->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) );
|
||||
config->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::Process_Zoom( wxCommandEvent& event )
|
||||
{
|
||||
int ii;
|
||||
|
||||
switch( event.GetId() )
|
||||
{
|
||||
case ID_ZOOM_PAGE:
|
||||
|
||||
for( ii = 0; ii < 4; ii++ )
|
||||
g_Parm_3D_Visu.m_Rot[ii] = 0.0;
|
||||
|
||||
g_Parm_3D_Visu.m_Zoom = 1.0;
|
||||
m_canvas->SetOffset( 0.0, 0.0 );
|
||||
trackball( g_Parm_3D_Visu.m_Quat, 0.0, 0.0, 0.0, 0.0 );
|
||||
break;
|
||||
|
||||
case ID_ZOOM_IN:
|
||||
g_Parm_3D_Visu.m_Zoom /= 1.2;
|
||||
|
||||
if( g_Parm_3D_Visu.m_Zoom <= 0.01 )
|
||||
g_Parm_3D_Visu.m_Zoom = 0.01;
|
||||
|
||||
break;
|
||||
|
||||
case ID_ZOOM_OUT:
|
||||
g_Parm_3D_Visu.m_Zoom *= 1.2;
|
||||
break;
|
||||
|
||||
case ID_ZOOM_REDRAW:
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
m_canvas->Refresh( false );
|
||||
m_canvas->DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
double EDA_3D_FRAME::BestZoom()
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
||||
{
|
||||
#define ROT_ANGLE 10.0
|
||||
int id = event.GetId();
|
||||
bool isChecked = event.IsChecked();
|
||||
|
||||
switch( id )
|
||||
{
|
||||
case ID_TOOL_SET_VISIBLE_ITEMS:
|
||||
Install_3D_ViewOptionDialog( event );
|
||||
break;
|
||||
|
||||
case ID_RELOAD3D_BOARD:
|
||||
NewDisplay();
|
||||
return;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_X_POS:
|
||||
g_Parm_3D_Visu.m_ROTX += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_X_NEG:
|
||||
g_Parm_3D_Visu.m_ROTX -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Y_POS:
|
||||
g_Parm_3D_Visu.m_ROTY += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Y_NEG:
|
||||
g_Parm_3D_Visu.m_ROTY -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Z_POS:
|
||||
g_Parm_3D_Visu.m_ROTZ += ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_ROTATE3D_Z_NEG:
|
||||
g_Parm_3D_Visu.m_ROTZ -= ROT_ANGLE;
|
||||
break;
|
||||
|
||||
case ID_MOVE3D_LEFT:
|
||||
m_canvas->SetView3D( WXK_LEFT );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_RIGHT:
|
||||
m_canvas->SetView3D( WXK_RIGHT );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_UP:
|
||||
m_canvas->SetView3D( WXK_UP );
|
||||
return;
|
||||
|
||||
case ID_MOVE3D_DOWN:
|
||||
m_canvas->SetView3D( WXK_DOWN );
|
||||
return;
|
||||
|
||||
case ID_ORTHO:
|
||||
ToggleOrtho();
|
||||
return;
|
||||
|
||||
case ID_TOOL_SCREENCOPY_TOCLIBBOARD:
|
||||
case ID_MENU_SCREENCOPY_PNG:
|
||||
case ID_MENU_SCREENCOPY_JPEG:
|
||||
m_canvas->TakeScreenshot( event );
|
||||
break;
|
||||
|
||||
case ID_MENU3D_BGCOLOR_SELECTION:
|
||||
Set3DBgColor();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_REALISTIC_MODE:
|
||||
g_Parm_3D_Visu.SetFlag( FL_USE_REALISTIC_MODE, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SHOW_BOARD_BODY:
|
||||
g_Parm_3D_Visu.SetFlag( FL_SHOW_BOARD_BODY, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_AXIS_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_AXIS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_MODULE_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_MODULE, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_USE_COPPER_THICKNESS:
|
||||
g_Parm_3D_Visu.SetFlag( FL_USE_COPPER_THICKNESS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ZONE_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_ZONE, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ADHESIVE_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_ADHESIVE, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SILKSCREEN_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_SILKSCREEN, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_MASK_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_SOLDERMASK, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_PASTE_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_SOLDERPASTE, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_COMMENTS_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_COMMENTS, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ECO_ONOFF:
|
||||
g_Parm_3D_Visu.SetFlag( FL_ECO, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
default:
|
||||
wxLogMessage( wxT( "EDA_3D_FRAME::Process_Special_Functions() error: unknown command" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
m_canvas->Refresh( true );
|
||||
m_canvas->DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event )
|
||||
{
|
||||
int id = event.GetId();
|
||||
|
||||
for( int ii = ID_MENU3D_GRID; ii < ID_MENU3D_GRID_END; ii++ )
|
||||
{
|
||||
if( event.GetId() == ii )
|
||||
continue;
|
||||
|
||||
GetMenuBar()->Check( ii, false );
|
||||
}
|
||||
|
||||
|
||||
switch( id )
|
||||
{
|
||||
case ID_MENU3D_GRID_NOGRID:
|
||||
g_Parm_3D_Visu.SetFlag( FL_GRID, false );
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_10_MM:
|
||||
g_Parm_3D_Visu.SetFlag( FL_GRID, true );
|
||||
g_Parm_3D_Visu.m_3D_Grid = 10.0;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_5_MM:
|
||||
g_Parm_3D_Visu.SetFlag( FL_GRID, true );
|
||||
g_Parm_3D_Visu.m_3D_Grid = 5.0;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_2P5_MM:
|
||||
g_Parm_3D_Visu.SetFlag( FL_GRID, true );
|
||||
g_Parm_3D_Visu.m_3D_Grid = 2.5;
|
||||
break;
|
||||
|
||||
case ID_MENU3D_GRID_1_MM:
|
||||
g_Parm_3D_Visu.SetFlag( FL_GRID, true );
|
||||
g_Parm_3D_Visu.m_3D_Grid = 1.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxLogMessage( wxT( "EDA_3D_FRAME::On3DGridSelection() error: unknown command" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
NewDisplay();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::NewDisplay()
|
||||
{
|
||||
m_reloadRequest = false;
|
||||
|
||||
m_canvas->ClearLists();
|
||||
m_canvas->CreateDrawGL_List();
|
||||
|
||||
// m_canvas->InitGL();
|
||||
m_canvas->Refresh( true );
|
||||
m_canvas->DisplayStatus();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_FRAME::OnActivate( wxActivateEvent& event )
|
||||
{
|
||||
// Reload data if 3D frame shows a footprint,
|
||||
// because it can be changed since last frame activation
|
||||
if( m_reloadRequest )
|
||||
NewDisplay();
|
||||
|
||||
event.Skip(); // required under wxMAC
|
||||
}
|
||||
|
||||
|
||||
/* called to set the background color of the 3D scene
|
||||
*/
|
||||
void EDA_3D_FRAME::Set3DBgColor()
|
||||
{
|
||||
S3D_COLOR color;
|
||||
wxColour newcolor, oldcolor;
|
||||
|
||||
oldcolor.Set( KiROUND( g_Parm_3D_Visu.m_BgColor.m_Red * 255 ),
|
||||
KiROUND( g_Parm_3D_Visu.m_BgColor.m_Green * 255 ),
|
||||
KiROUND( g_Parm_3D_Visu.m_BgColor.m_Blue * 255 ) );
|
||||
|
||||
newcolor = wxGetColourFromUser( this, oldcolor );
|
||||
|
||||
if( newcolor != oldcolor )
|
||||
{
|
||||
g_Parm_3D_Visu.m_BgColor.m_Red = (double) newcolor.Red() / 255.0;
|
||||
g_Parm_3D_Visu.m_BgColor.m_Green = (double) newcolor.Green() / 255.0;
|
||||
g_Parm_3D_Visu.m_BgColor.m_Blue = (double) newcolor.Blue() / 255.0;
|
||||
NewDisplay();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_math.cpp
|
||||
* @brief
|
||||
*/
|
||||
|
||||
|
||||
#include "3d_math.h"
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_math.h
|
||||
* @brief Defines math related functions
|
||||
*/
|
||||
|
||||
#ifndef _3D_MATH_H
|
||||
#define _3D_MATH_H
|
||||
|
||||
#include <plugins/3dapi/xv3d_types.h>
|
||||
#include "3d_fastmath.h"
|
||||
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
||||
*
|
||||
* @param aInclination θ ∈ [0, π]
|
||||
* @param aAzimuth φ ∈ [0, 2π]
|
||||
* @return Cartesian coordinates
|
||||
*/
|
||||
inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
|
||||
{
|
||||
float sinInc = glm::sin( aInclination );
|
||||
|
||||
return SFVEC3F( sinInc * glm::cos( aAzimuth ), sinInc * glm::sin( aAzimuth ),
|
||||
glm::cos( aInclination ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo This is not correct because it is not a gaussian random.
|
||||
*/
|
||||
inline SFVEC3F UniformRandomHemisphereDirection()
|
||||
{
|
||||
// It was experienced that this function is slow! do not use it :/
|
||||
// SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f,
|
||||
// (rand()/(float)RAND_MAX) - 0.5f,
|
||||
// (rand()/(float)RAND_MAX) - 0.5f );
|
||||
|
||||
SFVEC3F b( Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f, Fast_RandFloat() * 0.5f );
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
|
||||
inline SFVEC3F CosWeightedRandomHemisphereDirection( const SFVEC3F& n )
|
||||
{
|
||||
const float Xi1 = (float) rand() / (float) RAND_MAX;
|
||||
const float Xi2 = (float) rand() / (float) RAND_MAX;
|
||||
|
||||
const float theta = acos( sqrt( 1.0f - Xi1 ) );
|
||||
const float phi = 2.0f * glm::pi<float>() * Xi2;
|
||||
|
||||
const float xs = sinf( theta ) * cosf( phi );
|
||||
const float ys = cosf( theta );
|
||||
const float zs = sinf( theta ) * sinf( phi );
|
||||
|
||||
const SFVEC3F y( n.x, n.y, n.z );
|
||||
SFVEC3F h = y;
|
||||
|
||||
if( fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
|
||||
h.x= 1.0f;
|
||||
else if( fabs( h.y ) <= fabs( h.x ) && fabs( h.y ) <= fabs( h.z ) )
|
||||
h.y= 1.0f;
|
||||
else
|
||||
h.z= 1.0f;
|
||||
|
||||
|
||||
const SFVEC3F x = glm::normalize( glm::cross( h, y ) );
|
||||
const SFVEC3F z = glm::normalize( glm::cross( x, y ) );
|
||||
|
||||
SFVEC3F direction = xs * x + ys * y + zs * z;
|
||||
return glm::normalize( direction );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Based on:
|
||||
* https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
|
||||
* See also:
|
||||
* http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
|
||||
*
|
||||
* @param aInVector incoming vector.
|
||||
* @param aNormal normal in the intersection point.
|
||||
* @param aRin_over_Rout incoming refraction index / out refraction index.
|
||||
* @param aOutVector the refracted vector.
|
||||
* @return true
|
||||
*/
|
||||
inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout,
|
||||
SFVEC3F& aOutVector )
|
||||
{
|
||||
float cosThetaI = -glm::dot( aNormal, aInVector );
|
||||
float sin2ThetaI = glm::max( 0.0f, 1.0f - cosThetaI * cosThetaI );
|
||||
float sin2ThetaT = aRin_over_Rout * aRin_over_Rout * sin2ThetaI;
|
||||
|
||||
// Handle total internal reflection for transmission
|
||||
if( sin2ThetaT >= 1.0f )
|
||||
return false;
|
||||
|
||||
float cosThetaT = sqrtf( 1.0f - sin2ThetaT );
|
||||
|
||||
aOutVector = glm::normalize( aRin_over_Rout * aInVector +
|
||||
( aRin_over_Rout * cosThetaI - cosThetaT ) *
|
||||
aNormal );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max )
|
||||
{
|
||||
x = glm::clamp( x, in_min, in_max );
|
||||
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
inline float RGBtoGray( const SFVEC3F &aColor )
|
||||
{
|
||||
return (aColor.r * 0.2126f +
|
||||
aColor.g * 0.7152f +
|
||||
aColor.b * 0.0722f);
|
||||
}
|
||||
|
||||
inline SFVEC3F MaterialDiffuseToColorCAD( const SFVEC3F &aDiffuseColor )
|
||||
{
|
||||
// convert to a discret scale of grays
|
||||
const float luminance = glm::min(
|
||||
( ( (float) ( (unsigned int) ( 4.0f * RGBtoGray( aDiffuseColor ) ) ) + 0.5f ) / 4.0f )
|
||||
* 1.0f,
|
||||
1.0f );
|
||||
|
||||
const float maxValue = glm::max( glm::max( glm::max( aDiffuseColor.r, aDiffuseColor.g ),
|
||||
aDiffuseColor.b ), FLT_EPSILON );
|
||||
|
||||
return ( aDiffuseColor / SFVEC3F( maxValue ) ) * 0.125f + luminance * 0.875f;
|
||||
}
|
||||
|
||||
|
||||
// http://fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJ4KngqMiIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MCwiZXEiOiItKCh4LTEpXjIpKjIrMSIsImNvbG9yIjoiIzAwMDAwMCJ9LHsidHlwZSI6MTAwMCwid2luZG93IjpbIi0xLjM4NzUwMDAwMDAwMDAwMDIiLCIxLjg2MjQ5OTk5OTk5OTk5OTgiLCItMC43IiwiMS4zIl19XQ--
|
||||
inline float QuadricEasingInOut( float t )
|
||||
{
|
||||
if( t <= 0.5f )
|
||||
{
|
||||
return t * t * 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = t - 1.0f;
|
||||
|
||||
return -2.0f * ( t * t ) + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// http://www.wolframalpha.com/input/?i=t%5E2(3-2t)
|
||||
inline float BezierBlend( float t )
|
||||
{
|
||||
return t * t * ( 3.0f - 2.0f * t );
|
||||
}
|
||||
|
||||
#endif // 3D_MATH_H
|
||||
@@ -1,481 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Implements a model viewer canvas. The purpose of the model viewer is to render
|
||||
* 3d models that come in the original data from the files without any transformations.
|
||||
*/
|
||||
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
#include <iostream>
|
||||
#include "3d_rendering/opengl/3d_model.h"
|
||||
#include "eda_3d_model_viewer.h"
|
||||
#include "../3d_rendering/opengl/opengl_utils.h"
|
||||
#include "../3d_cache/3d_cache.h"
|
||||
#include <wx/dcclient.h>
|
||||
#include <base_units.h>
|
||||
#include <gl_context_mgr.h>
|
||||
#include <settings/common_settings.h>
|
||||
#include <pgm_base.h>
|
||||
#include <gal/dpi_scaling.h>
|
||||
#include <macros.h>
|
||||
|
||||
/**
|
||||
* Scale conversion from 3d model units to pcb units
|
||||
*/
|
||||
#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* EDA_3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( EDA_3D_MODEL_VIEWER, wxGLCanvas )
|
||||
EVT_PAINT( EDA_3D_MODEL_VIEWER::OnPaint )
|
||||
|
||||
// mouse events
|
||||
EVT_LEFT_DOWN( EDA_3D_MODEL_VIEWER::OnLeftDown )
|
||||
EVT_LEFT_UP( EDA_3D_MODEL_VIEWER::OnLeftUp )
|
||||
EVT_MIDDLE_UP( EDA_3D_MODEL_VIEWER::OnMiddleUp )
|
||||
EVT_MIDDLE_DOWN( EDA_3D_MODEL_VIEWER::OnMiddleDown)
|
||||
EVT_RIGHT_DOWN( EDA_3D_MODEL_VIEWER::OnRightClick )
|
||||
EVT_MOUSEWHEEL( EDA_3D_MODEL_VIEWER::OnMouseWheel )
|
||||
EVT_MOTION( EDA_3D_MODEL_VIEWER::OnMouseMove )
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
EVT_MAGNIFY( EDA_3D_MODEL_VIEWER::OnMagnify )
|
||||
#endif
|
||||
|
||||
// other events
|
||||
EVT_ERASE_BACKGROUND( EDA_3D_MODEL_VIEWER::OnEraseBackground )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
// This defines the range that all coord will have to be rendered.
|
||||
// It will use this value to convert to a normalized value between
|
||||
// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
|
||||
#define RANGE_SCALE_3D 8.0f
|
||||
|
||||
|
||||
EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER( wxWindow* aParent, const int* aAttribList,
|
||||
S3D_CACHE* aCacheManager ) :
|
||||
HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE ),
|
||||
m_trackBallCamera( RANGE_SCALE_3D * 4.0f ),
|
||||
m_cacheManager( aCacheManager )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::EDA_3D_MODEL_VIEWER" ) );
|
||||
|
||||
m_ogl_initialized = false;
|
||||
m_reload_is_needed = false;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
m_3d_model = nullptr;
|
||||
m_BiuTo3dUnits = 1.0;
|
||||
|
||||
m_glRC = nullptr;
|
||||
|
||||
COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
|
||||
|
||||
const DPI_SCALING dpi{ settings, this };
|
||||
SetScaleFactor( dpi.GetScaleFactor() );
|
||||
}
|
||||
|
||||
|
||||
EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER" ) );
|
||||
|
||||
if( m_glRC )
|
||||
{
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
|
||||
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Set3DModel( const S3DMODEL& a3DModel )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a S3DMODEL" ) );
|
||||
|
||||
// Validate a3DModel pointers
|
||||
wxASSERT( a3DModel.m_Materials != nullptr );
|
||||
wxASSERT( a3DModel.m_Meshes != nullptr );
|
||||
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
||||
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
||||
|
||||
// Delete the old model
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
m_3d_model = nullptr;
|
||||
|
||||
if( ( a3DModel.m_Materials != nullptr ) && ( a3DModel.m_Meshes != nullptr )
|
||||
&& ( a3DModel.m_MaterialsSize > 0 ) && ( a3DModel.m_MeshesSize > 0 ) )
|
||||
{
|
||||
m_3d_model = &a3DModel;
|
||||
m_reload_is_needed = true;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Set3DModel( const wxString& aModelPathName)
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::Set3DModel with a wxString" ) );
|
||||
|
||||
if( m_cacheManager )
|
||||
{
|
||||
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName, wxEmptyString );
|
||||
|
||||
if( model )
|
||||
Set3DModel( (const S3DMODEL &)*model );
|
||||
else
|
||||
Clear3DModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::Clear3DModel()
|
||||
{
|
||||
// Delete the old model
|
||||
m_reload_is_needed = false;
|
||||
|
||||
delete m_ogl_3dmodel;
|
||||
m_ogl_3dmodel = nullptr;
|
||||
|
||||
m_3d_model = nullptr;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::ogl_initialize()
|
||||
{
|
||||
const GLenum err = glewInit();
|
||||
|
||||
if( GLEW_OK != err )
|
||||
{
|
||||
const wxString msgError = (const char*) glewGetErrorString( err );
|
||||
|
||||
wxLogMessage( msgError );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::ogl_initialize Using GLEW version %s" ),
|
||||
FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
|
||||
}
|
||||
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
|
||||
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
|
||||
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glEnable( GL_CULL_FACE );
|
||||
glShadeModel( GL_SMOOTH );
|
||||
glEnable( GL_LINE_SMOOTH );
|
||||
glEnable( GL_NORMALIZE );
|
||||
|
||||
// Setup light
|
||||
// https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
|
||||
const GLfloat ambient[] = { 0.01f, 0.01f, 0.01f, 1.0f };
|
||||
const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
// defines a directional light that points along the negative z-axis
|
||||
const GLfloat position[] = { 0.0f, 0.0f, 2.0f * RANGE_SCALE_3D, 0.0f };
|
||||
|
||||
const GLfloat lmodel_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
|
||||
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
|
||||
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, position );
|
||||
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::ogl_set_arrow_material()
|
||||
{
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
|
||||
const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
|
||||
|
||||
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
|
||||
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
{
|
||||
event.Skip( false );
|
||||
|
||||
// SwapBuffer requires the window to be shown before calling
|
||||
if( !IsShownOnScreen() )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint !IsShown" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// "Makes the OpenGL state that is represented by the OpenGL rendering
|
||||
// context context current, i.e. it will be used by all subsequent OpenGL calls.
|
||||
// This function may only be called when the window is shown on screen"
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint creating gl context failed" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
// This is done here rather than in a wxSizeEvent handler because our
|
||||
// OpenGL rendering context (and thus viewport setting) is used with
|
||||
// multiple canvases: If we updated the viewport in the wxSizeEvent
|
||||
// handler, changing the size of one canvas causes a viewport setting that
|
||||
// is wrong when next another canvas is repainted.
|
||||
wxSize clientSize = GetNativePixelSize();
|
||||
|
||||
if( !m_ogl_initialized )
|
||||
{
|
||||
m_ogl_initialized = true;
|
||||
ogl_initialize();
|
||||
}
|
||||
|
||||
if( m_reload_is_needed )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
|
||||
|
||||
m_reload_is_needed = false;
|
||||
m_ogl_3dmodel = new MODEL_3D( *m_3d_model, MATERIAL_MODE::NORMAL );
|
||||
|
||||
// It convert a model as it was a board, so get the max size dimension of the board
|
||||
// and compute the conversion scale
|
||||
m_BiuTo3dUnits =
|
||||
(double) RANGE_SCALE_3D
|
||||
/ ( (double) m_ogl_3dmodel->GetBBox().GetMaxDimension() * UNITS3D_TO_UNITSPCB );
|
||||
}
|
||||
|
||||
glViewport( 0, 0, clientSize.x, clientSize.y );
|
||||
|
||||
m_trackBallCamera.SetCurWindowSize( clientSize );
|
||||
|
||||
// clear color and depth buffers
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
glClearDepth( 1.0f );
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// Set projection and modelview matrices
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetProjectionMatrix() ) );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
|
||||
glEnable( GL_LIGHTING );
|
||||
glEnable( GL_LIGHT0 );
|
||||
|
||||
// Render Model
|
||||
if( m_ogl_3dmodel )
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
double modelunit_to_3d_units_factor = m_BiuTo3dUnits * UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
|
||||
modelunit_to_3d_units_factor );
|
||||
|
||||
// Center model in the render viewport
|
||||
const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
|
||||
|
||||
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
|
||||
|
||||
m_ogl_3dmodel->BeginDrawMulti( true );
|
||||
|
||||
m_ogl_3dmodel->DrawOpaque( false );
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDepthMask( GL_TRUE );
|
||||
|
||||
m_ogl_3dmodel->EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// YxY squared view port
|
||||
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 );
|
||||
glClear( GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
gluPerspective( 45.0f, 1.0f, 0.01f, RANGE_SCALE_3D * 2.0f );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
const glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f),
|
||||
SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
|
||||
|
||||
const glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
|
||||
|
||||
glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
|
||||
|
||||
ogl_set_arrow_material();
|
||||
|
||||
glColor3f( 0.9f, 0.0f, 0.0f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( RANGE_SCALE_3D / 2.65f, 0.0f, 0.0f ),
|
||||
0.275f );
|
||||
|
||||
glColor3f( 0.0f, 0.9f, 0.0f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, RANGE_SCALE_3D / 2.65f, 0.0f ),
|
||||
0.275f );
|
||||
|
||||
glColor3f( 0.0f, 0.0f, 0.9f );
|
||||
DrawRoundArrow( SFVEC3F( 0.0f, 0.0f, 0.0f ), SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 2.65f ),
|
||||
0.275f );
|
||||
|
||||
// "Swaps the double-buffer of this window, making the back-buffer the
|
||||
// front-buffer and vice versa, so that the output of the previous OpenGL
|
||||
// commands is displayed on the window."
|
||||
SwapBuffers();
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent& event )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnEraseBackground" ) );
|
||||
// Do nothing, to avoid flashing.
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent& event )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnMouseWheel" ) );
|
||||
|
||||
if( event.ShiftDown() )
|
||||
{
|
||||
//if( event.GetWheelRotation() < 0 )
|
||||
//SetView3D( WXK_UP ); // move up
|
||||
//else
|
||||
//SetView3D( WXK_DOWN ); // move down
|
||||
}
|
||||
else if( event.ControlDown() )
|
||||
{
|
||||
//if( event.GetWheelRotation() > 0 )
|
||||
//SetView3D( WXK_RIGHT ); // move right
|
||||
//else
|
||||
//SetView3D( WXK_LEFT ); // move left
|
||||
}
|
||||
else
|
||||
{
|
||||
m_trackBallCamera.Zoom( event.GetWheelRotation() > 0 ? 1.1f : 1/1.1f );
|
||||
|
||||
//DisplayStatus();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void EDA_3D_MODEL_VIEWER::OnMagnify( wxMouseEvent& event )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
const wxSize& nativeWinSize = GetNativePixelSize();
|
||||
const wxPoint& nativePosition = GetNativePosition( event.GetPosition() );
|
||||
|
||||
m_trackBallCamera.SetCurWindowSize( nativeWinSize );
|
||||
|
||||
if( event.Dragging() )
|
||||
{
|
||||
if( event.LeftIsDown() ) // Drag
|
||||
m_trackBallCamera.Drag( nativePosition );
|
||||
|
||||
// orientation has changed, redraw mesh
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
m_trackBallCamera.SetCurMousePosition( nativePosition );
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_MODEL_VIEWER::OnRightClick( wxMouseEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c3d_model_viewer.h
|
||||
* @brief Implements a model viewer canvas.
|
||||
*
|
||||
* The purpose of model viewer is to render 3d models that come in the original data from
|
||||
* the files without any transformations.
|
||||
*/
|
||||
|
||||
#ifndef _C3D_MODEL_VIEWER_H_
|
||||
#define _C3D_MODEL_VIEWER_H_
|
||||
|
||||
#include "3d_rendering/track_ball.h"
|
||||
#include <gal/hidpi_gl_canvas.h>
|
||||
|
||||
class S3D_CACHE;
|
||||
class MODEL_3D;
|
||||
|
||||
/**
|
||||
* Implement a canvas based on a wxGLCanvas.
|
||||
*/
|
||||
class EDA_3D_MODEL_VIEWER : public HIDPI_GL_CANVAS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new 3D Canvas with a attribute list.
|
||||
*
|
||||
* @param aParent the parent creator of this canvas.
|
||||
* @param aAttribList a list of openGL options created by #OGL_ATT_LIST::GetAttributesList.
|
||||
*/
|
||||
EDA_3D_MODEL_VIEWER( wxWindow* aParent, const int* aAttribList = nullptr,
|
||||
S3D_CACHE* aCacheManager = nullptr );
|
||||
|
||||
~EDA_3D_MODEL_VIEWER();
|
||||
|
||||
/**
|
||||
* Set this model to be displayed.
|
||||
*
|
||||
* @param a3DModel 3D model data.
|
||||
*/
|
||||
void Set3DModel( const S3DMODEL& a3DModel );
|
||||
|
||||
/**
|
||||
* Set this model to be displayed.
|
||||
*
|
||||
* @param aModelPathName 3D model path name.
|
||||
*/
|
||||
void Set3DModel( const wxString& aModelPathName );
|
||||
|
||||
/**
|
||||
* Unload the displayed 3D model.
|
||||
*/
|
||||
void Clear3DModel();
|
||||
|
||||
private:
|
||||
void ogl_initialize();
|
||||
void ogl_set_arrow_material();
|
||||
|
||||
void OnPaint( wxPaintEvent& event );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnMouseWheel( wxMouseEvent& event );
|
||||
|
||||
#ifdef USE_OSX_MAGNIFY_EVENT
|
||||
void OnMagnify( wxMouseEvent& event );
|
||||
#endif
|
||||
|
||||
void OnMouseMove( wxMouseEvent& event );
|
||||
|
||||
void OnLeftDown( wxMouseEvent& event );
|
||||
|
||||
void OnLeftUp( wxMouseEvent& event );
|
||||
|
||||
void OnMiddleUp( wxMouseEvent& event );
|
||||
|
||||
void OnMiddleDown( wxMouseEvent& event );
|
||||
|
||||
void OnRightClick( wxMouseEvent& event );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
/// openGL context
|
||||
wxGLContext* m_glRC;
|
||||
|
||||
/// Camera used in this canvas
|
||||
TRACK_BALL m_trackBallCamera;
|
||||
|
||||
/// Original 3d model data
|
||||
const S3DMODEL* m_3d_model;
|
||||
|
||||
/// Class holder for 3d model to display on openGL
|
||||
MODEL_3D* m_ogl_3dmodel;
|
||||
|
||||
/// Flag that we have a new model and it need to be reloaded when the paint is called
|
||||
bool m_reload_is_needed;
|
||||
|
||||
/// Flag if open gl was initialized
|
||||
bool m_ogl_initialized;
|
||||
|
||||
/// factor to convert the model or any other items to keep it in relation to
|
||||
/// the +/-RANGE_SCALE_3D
|
||||
/// (it is named same as the board render for better understanding proposes)
|
||||
double m_BiuTo3dUnits;
|
||||
|
||||
/// Optional cache manager
|
||||
S3D_CACHE* m_cacheManager;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
#endif // _C3D_MODEL_VIEWER_H_
|
||||
@@ -1,25 +0,0 @@
|
||||
add_library(3d-viewer_navlib STATIC
|
||||
"nl_3d_viewer_plugin.cpp"
|
||||
"nl_3d_viewer_plugin_impl.cpp"
|
||||
)
|
||||
|
||||
# 3d-viewer_navlib depends on make_lexer outputs in common
|
||||
add_dependencies( 3d-viewer_navlib pcbcommon )
|
||||
|
||||
# Find the 3DxWare SDK component 3DxWare::NlClient
|
||||
# find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib)
|
||||
target_compile_definitions(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_DEFINITIONS>
|
||||
)
|
||||
target_compile_options(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_OPTIONS>
|
||||
)
|
||||
target_include_directories(3d-viewer_navlib PRIVATE
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:pcbnew_kiface_objects,INCLUDE_DIRECTORIES>
|
||||
)
|
||||
target_link_libraries(3d-viewer_navlib
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES>
|
||||
3DxWare::Navlib
|
||||
)
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_3d_viewer_plugin.h"
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
#include <advanced_config.h>
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
m_impl = new NL_3D_VIEWER_PLUGIN_IMPL( aViewport );
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
m_impl->SetFocus( focus );
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_3d_viewer_plugin.h
|
||||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN class
|
||||
*/
|
||||
|
||||
#ifndef NL_3D_VIEWER_PLUGIN_H_
|
||||
#define NL_3D_VIEWER_PLUGIN_H_
|
||||
|
||||
// Forward declarations.
|
||||
class EDA_3D_CANVAS;
|
||||
class NL_3D_VIEWER_PLUGIN_IMPL;
|
||||
|
||||
/**
|
||||
* The class that implements the public interface to the SpaceMouse plug-in.
|
||||
*/
|
||||
class NL_3D_VIEWER_PLUGIN
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new instance of the NL_3D_VIEWER_PLUGIN.
|
||||
*
|
||||
* @param aViewport is the viewport to be navigated.
|
||||
*/
|
||||
NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport );
|
||||
|
||||
virtual ~NL_3D_VIEWER_PLUGIN();
|
||||
|
||||
/**
|
||||
* Set the connection to the 3Dconnexion driver to the focus state so that
|
||||
* 3DMouse data is routed here.
|
||||
*
|
||||
* @param aFocus is true to set the connection active.
|
||||
*/
|
||||
void SetFocus( bool aFocus = true );
|
||||
|
||||
private:
|
||||
NL_3D_VIEWER_PLUGIN_IMPL* m_impl;
|
||||
};
|
||||
|
||||
#endif // NL_3D_VIEWER_PLUGIN_H_
|
||||
@@ -1,659 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
|
||||
// 3d-viewer
|
||||
#include <3d-viewer/3d_rendering/track_ball.h>
|
||||
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
|
||||
|
||||
// KiCAD includes
|
||||
#include <tool/action_manager.h>
|
||||
#include <tool/tool_manager.h>
|
||||
|
||||
// stdlib
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/mstream.h>
|
||||
|
||||
/**
|
||||
* Flag to enable the NL_3D_VIEWER_PLUGIN debug tracing.
|
||||
*
|
||||
* Use "KI_TRACE_NL_3D_VIEWER_PLUGIN" to enable.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* NL_3D_VIEWER_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_3D_VIEWER_PLUGIN" );
|
||||
|
||||
|
||||
/**
|
||||
* Template to compare two glm::mat<T> values for equality within a required epsilon.
|
||||
*
|
||||
* @param aFirst value to compare.
|
||||
* @param aSecond value to compare.
|
||||
* @param aEpsilon allowed error.
|
||||
* @return true if the values considered equal within the specified epsilon, otherwise false.
|
||||
*/
|
||||
template <glm::length_t L, glm::length_t C, class T, glm::qualifier Q>
|
||||
bool equals( glm::mat<L, C, T, Q> const& aFirst, glm::mat<L, C, T, Q> const& aSecond,
|
||||
T aEpsilon = static_cast<T>( FLT_EPSILON * 10 ) )
|
||||
{
|
||||
T const* first = glm::value_ptr( aFirst );
|
||||
T const* second = glm::value_ptr( aSecond );
|
||||
|
||||
for( glm::length_t j = 0; j < L * C; ++j )
|
||||
{
|
||||
if( !equals( first[j], second[j], aEpsilon ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas ) :
|
||||
NAV_3D( false, false ), m_canvas( aCanvas ), m_capIsMoving( false )
|
||||
{
|
||||
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() );
|
||||
|
||||
PutProfileHint( "KiCAD 3D" );
|
||||
|
||||
EnableNavigation( true );
|
||||
PutFrameTimingSource( TimingSource::SpaceMouse );
|
||||
|
||||
exportCommandsAndImages();
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN_IMPL::~NL_3D_VIEWER_PLUGIN_IMPL()
|
||||
{
|
||||
EnableNavigation( false );
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN_IMPL::SetFocus( bool aFocus )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::SetFocus %d" ), aFocus );
|
||||
NAV_3D::Write( navlib::focus_k, aFocus );
|
||||
}
|
||||
|
||||
// temporary store for the categories
|
||||
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
|
||||
|
||||
/**
|
||||
* Add a category to the store.
|
||||
*
|
||||
* The function adds category paths of the format "A.B" where B is a sub-category of A.
|
||||
*
|
||||
* @param aCategoryPath is the std::string representation of the category.
|
||||
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
|
||||
* @return a CATEGORY_STORE::iterator where the category was added.
|
||||
*/
|
||||
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore )
|
||||
{
|
||||
using TDx::SpaceMouse::CCategory;
|
||||
|
||||
CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
|
||||
std::string::size_type pos = aCategoryPath.find_last_of( '.' );
|
||||
|
||||
if( pos != std::string::npos )
|
||||
{
|
||||
std::string parentPath = aCategoryPath.substr( 0, pos );
|
||||
parent_iter = aCategoryStore.find( parentPath );
|
||||
|
||||
if( parent_iter == aCategoryStore.end() )
|
||||
{
|
||||
parent_iter = add_category( parentPath, aCategoryStore );
|
||||
}
|
||||
}
|
||||
|
||||
std::string name = aCategoryPath.substr( pos + 1 );
|
||||
std::unique_ptr<CCategory> categoryNode =
|
||||
std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
|
||||
|
||||
CATEGORY_STORE::iterator iter = aCategoryStore.insert(
|
||||
aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
|
||||
|
||||
parent_iter->second->push_back( std::move( categoryNode ) );
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages()
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages" ) );
|
||||
|
||||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
||||
|
||||
if( actions.size() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using TDx::SpaceMouse::CCommand;
|
||||
using TDx::SpaceMouse::CCommandSet;
|
||||
|
||||
// The root action set node
|
||||
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
|
||||
|
||||
// Activate the command set
|
||||
NAV_3D::PutActiveCommands( commandSet.GetId() );
|
||||
|
||||
// temporary store for the categories
|
||||
CATEGORY_STORE categoryStore;
|
||||
|
||||
std::vector<TDx::CImage> vImages;
|
||||
|
||||
// add the action set to the category_store
|
||||
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
|
||||
|
||||
std::list<TOOL_ACTION*>::const_iterator it;
|
||||
|
||||
for( it = actions.begin(); it != actions.end(); ++it )
|
||||
{
|
||||
const TOOL_ACTION* action = *it;
|
||||
std::string label = action->GetLabel().ToStdString();
|
||||
|
||||
if( label.empty() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = action->GetName();
|
||||
|
||||
// Do no export commands for the pcbnew app.
|
||||
if( name.rfind( "pcbnew.", 0 ) == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strCategory = action->GetToolName();
|
||||
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
|
||||
|
||||
if( iter == categoryStore.end() )
|
||||
{
|
||||
iter = add_category( std::move( strCategory ), categoryStore );
|
||||
}
|
||||
|
||||
std::string description = action->GetDescription().ToStdString();
|
||||
|
||||
// Arbitrary 8-bit data stream
|
||||
wxMemoryOutputStream imageStream;
|
||||
|
||||
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
|
||||
{
|
||||
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
|
||||
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
|
||||
image.Destroy();
|
||||
|
||||
if( imageStream.GetSize() )
|
||||
{
|
||||
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
|
||||
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
|
||||
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
|
||||
streamBuffer->GetBufferStart() ),
|
||||
streamBuffer->GetBufferSize() ),
|
||||
0 );
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
|
||||
vImages.push_back( std::move( tdxImage ) );
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
|
||||
name, description, iter->first );
|
||||
|
||||
iter->second->push_back(
|
||||
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
|
||||
}
|
||||
|
||||
NAV_3D::AddCommandSet( commandSet );
|
||||
NAV_3D::AddImages( vImages );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
// cache the camera matrix so that we can tell if the view has been moved and
|
||||
// calculate a delta transform if required.
|
||||
m_cameraMatrix = m_camera->GetViewMatrix();
|
||||
|
||||
std::copy_n( glm::value_ptr( glm::inverse( m_cameraMatrix ) ), 16, matrix.m );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
|
||||
{
|
||||
SFVEC3F origin, direction;
|
||||
m_camera->MakeRayAtCurrentMousePosition( origin, direction );
|
||||
|
||||
position = { origin.x, origin.y, origin.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
if( m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
double half_width = f.fw / 2.;
|
||||
double half_height = f.fh / 2.;
|
||||
extents = { -half_width, -half_height, f.nearD, half_width, half_height, f.farD };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFOV( double& aFov ) const
|
||||
{
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
aFov = glm::radians( f.angle );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& aFrustum ) const
|
||||
{
|
||||
if( m_camera->GetProjection() != PROJECTION_TYPE::PERSPECTIVE )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
double half_width = f.nw / 2.;
|
||||
double half_height = f.nh / 2.;
|
||||
aFrustum = { -half_width, half_width, -half_height, half_height, f.nearD, f.farD };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
|
||||
{
|
||||
perspective = m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& aCameraMatrix )
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
glm::mat4 cam, viewMatrix;
|
||||
std::copy_n( aCameraMatrix.m, 16, glm::value_ptr( cam ) );
|
||||
viewMatrix = glm::inverse( cam );
|
||||
|
||||
glm::mat4 camera = m_camera->GetViewMatrix();
|
||||
|
||||
// The navlib does not move the camera in its z-axis in an orthographic projection
|
||||
// as this does not change the viewed object size. However ...
|
||||
|
||||
if( m_camera->GetProjection() == PROJECTION_TYPE::ORTHO )
|
||||
{
|
||||
// ... the CAMERA class couples zoom and distance to the object: we need to
|
||||
// ensure that The CAMERA's z position relative to the lookat_pos is not changed
|
||||
// in an orthographic projection.
|
||||
glm::vec4 lookat( m_camera->GetLookAtPos(), 1.0f );
|
||||
glm::vec4 lookat_new = viewMatrix * lookat;
|
||||
glm::vec4 lookat_old = camera * lookat;
|
||||
|
||||
viewMatrix[3].z += lookat_old.z - lookat_new.z;
|
||||
}
|
||||
|
||||
if( !equals( camera, m_cameraMatrix ) )
|
||||
{
|
||||
// Some other input device has moved the camera. Apply only the intended delta
|
||||
// transform ...
|
||||
m_camera->SetViewMatrix( viewMatrix * glm::inverse( m_cameraMatrix ) * camera );
|
||||
m_camera->Update();
|
||||
|
||||
// .., cache the intended camera matrix so that we can calculate the delta
|
||||
// transform when needed ...
|
||||
m_cameraMatrix = viewMatrix;
|
||||
|
||||
// ... and let the 3DMouse controller know, that something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
m_camera->SetViewMatrix( viewMatrix );
|
||||
m_camera->Update();
|
||||
|
||||
// cache the view matrix so that we know when it has changed.
|
||||
m_cameraMatrix = m_camera->GetViewMatrix();
|
||||
|
||||
// The camera has a constraint on the z position so we need to check that ...
|
||||
|
||||
if( !equals( m_cameraMatrix[3].z, viewMatrix[3].z ) )
|
||||
{
|
||||
// ... and let the 3DMouse controller know, when something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
|
||||
{
|
||||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum();
|
||||
|
||||
float factor = f.nw / ( extents.max_x - extents.min_x );
|
||||
float zoom = m_camera->GetZoom() / factor;
|
||||
|
||||
m_camera->Zoom( factor );
|
||||
|
||||
// The camera auto positions the camera to match the zoom values. We need to
|
||||
// update our cached camera matrix to match the new z value
|
||||
m_cameraMatrix[3].z = m_camera->GetViewMatrix()[3].z;
|
||||
|
||||
// The camera has a constraint on the zoom factor so we need to check that ...
|
||||
if( zoom != m_camera->GetZoom() )
|
||||
{
|
||||
// ... and let the 3DMouse controller know, when something is amiss.
|
||||
return navlib::make_result_code( navlib::navlib_errc::error );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFOV( double fov )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::permission_denied );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
SFVEC3F min = m_canvas->GetBoardAdapter().GetBBox().Min();
|
||||
SFVEC3F max = m_canvas->GetBoardAdapter().GetBBox().Max();
|
||||
|
||||
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const
|
||||
{
|
||||
empty = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
|
||||
{
|
||||
SFVEC3F lap = m_camera->GetLookAtPos();
|
||||
|
||||
position = { lap.x, lap.y, lap.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
|
||||
{
|
||||
userPivot = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
|
||||
{
|
||||
SFVEC3F pivotPos = SFVEC3F( position.x, position.y, position.z );
|
||||
|
||||
// Set the 3dmouse pivot position.
|
||||
m_canvas->Set3dmousePivotPos( pivotPos );
|
||||
|
||||
// Set the camera lookat pos.
|
||||
m_camera->SetLookAtPos_T1( pivotPos );
|
||||
|
||||
m_canvas->Request_refresh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
|
||||
{
|
||||
visible = m_canvas->GetRender3dmousePivot();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotVisible( bool visible )
|
||||
{
|
||||
m_canvas->SetRender3dmousePivot( visible );
|
||||
|
||||
m_canvas->Request_refresh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
|
||||
{
|
||||
RAY mouseRay;
|
||||
mouseRay.Init( m_rayOrigin, m_rayDirection );
|
||||
|
||||
float hit;
|
||||
glm::vec3 vec;
|
||||
|
||||
// Test it with the board bounding box
|
||||
|
||||
if( m_canvas->GetBoardAdapter().GetBBox().Intersect( mouseRay, &hit ) )
|
||||
{
|
||||
vec = mouseRay.at( hit );
|
||||
position = { vec.x, vec.y, vec.z };
|
||||
return 0;
|
||||
}
|
||||
|
||||
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitAperture( double aperture )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
|
||||
{
|
||||
m_rayDirection = { direction.x, direction.y, direction.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
|
||||
{
|
||||
m_rayOrigin = { eye.x, eye.y, eye.z };
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
|
||||
{
|
||||
if( commandId.empty() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
||||
TOOL_ACTION* context = nullptr;
|
||||
|
||||
for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
|
||||
{
|
||||
TOOL_ACTION* action = *it;
|
||||
std::string nm = action->GetName();
|
||||
|
||||
if( commandId == nm )
|
||||
{
|
||||
context = action;
|
||||
}
|
||||
}
|
||||
|
||||
if( context != nullptr )
|
||||
{
|
||||
wxWindow* parent = m_canvas->GetParent();
|
||||
|
||||
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
|
||||
// currently active.
|
||||
|
||||
if( parent->IsEnabled() )
|
||||
{
|
||||
TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->GetToolManager();
|
||||
|
||||
if( tool_manager == nullptr )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
|
||||
// Get the selection to use to test if the action is enabled
|
||||
SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
|
||||
|
||||
bool runAction = true;
|
||||
|
||||
if( const ACTION_CONDITIONS* aCond =
|
||||
tool_manager->GetActionManager()->GetCondition( *context ) )
|
||||
{
|
||||
runAction = aCond->enableCondition( sel );
|
||||
}
|
||||
|
||||
if( runAction )
|
||||
{
|
||||
tool_manager->RunAction( *context, true );
|
||||
m_canvas->Request_refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSettingsChanged( long change )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetMotionFlag( bool value )
|
||||
{
|
||||
m_capIsMoving = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetTransaction( long value )
|
||||
{
|
||||
if( value != 0L )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
m_canvas->Request_refresh( true );
|
||||
wxLogTrace( m_logTrace, wxT( "End of transaction" ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
|
||||
{
|
||||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported );
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 };
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
|
||||
{
|
||||
// Use the right-handed coordinate system X-right, Z-up, Y-in (row vectors)
|
||||
matrix = { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1 };
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
|
||||
{
|
||||
isRotatable = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 3Dconnexion
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nl_3d_viewer_plugin_impl.h
|
||||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN_IMPL class
|
||||
*/
|
||||
|
||||
#ifndef NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
#define NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
|
||||
// TDxWare SDK.
|
||||
#include <SpaceMouse/CNavigation3D.hpp>
|
||||
|
||||
// KiCAD
|
||||
#include <include/plugins/3dapi/xv3d_types.h>
|
||||
|
||||
// wx
|
||||
#include <wx/chartype.h>
|
||||
|
||||
// glm
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// Forward declarations.
|
||||
class EDA_3D_CANVAS;
|
||||
class TRACK_BALL;
|
||||
|
||||
// Convenience typedef.
|
||||
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D;
|
||||
|
||||
/**
|
||||
* The class that implements the accessors and mutators required for
|
||||
* 3D navigation in an EDA_3D_CANVAS using a SpaceMouse.
|
||||
*/
|
||||
class NL_3D_VIEWER_PLUGIN_IMPL : public NAV_3D
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new instance of the NL_3DVIEWER_PLUGIN.
|
||||
*
|
||||
* @param aCanvas is the viewport to be navigated.
|
||||
*/
|
||||
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
|
||||
|
||||
virtual ~NL_3D_VIEWER_PLUGIN_IMPL();
|
||||
|
||||
/**
|
||||
* Set the connection to the 3Dconnexion driver to the focus state so that
|
||||
* 3DMouse data is routed here.
|
||||
*
|
||||
* @param aFocus is true to set the connection active.
|
||||
*/
|
||||
void SetFocus( bool aFocus = true );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Export the invocable actions and images to the 3Dconnexion UI.
|
||||
*/
|
||||
void exportCommandsAndImages();
|
||||
|
||||
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetPointerPosition( navlib::point_t& aPosition ) const override;
|
||||
long GetViewExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetViewFOV( double& aFov ) const override;
|
||||
long GetViewFrustum( navlib::frustum_t& aFrustum ) const override;
|
||||
long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override;
|
||||
long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override;
|
||||
long SetViewExtents( const navlib::box_t& aExtents ) override;
|
||||
long SetViewFOV( double aFov ) override;
|
||||
long SetViewFrustum( const navlib::frustum_t& aFrustum ) override;
|
||||
long GetModelExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetSelectionExtents( navlib::box_t& aExtents ) const override;
|
||||
long GetSelectionTransform( navlib::matrix_t& aTransform ) const override;
|
||||
long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override;
|
||||
long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override;
|
||||
long GetPivotPosition( navlib::point_t& aPosition ) const override;
|
||||
long IsUserPivot( navlib::bool_t& aUserPivot ) const override;
|
||||
long SetPivotPosition( const navlib::point_t& aPosition ) override;
|
||||
long GetPivotVisible( navlib::bool_t& aVisible ) const override;
|
||||
long SetPivotVisible( bool aVisible ) override;
|
||||
long GetHitLookAt( navlib::point_t& aPosition ) const override;
|
||||
long SetHitAperture( double aAperture ) override;
|
||||
long SetHitDirection( const navlib::vector_t& aDirection ) override;
|
||||
long SetHitLookFrom( const navlib::point_t& aPosition ) override;
|
||||
long SetHitSelectionOnly( bool aSelectionOnly ) override;
|
||||
long SetActiveCommand( std::string aCommandId ) override;
|
||||
|
||||
long SetSettingsChanged( long aChangeNumber ) override;
|
||||
long SetMotionFlag( bool aValue ) override;
|
||||
long SetTransaction( long aValue ) override;
|
||||
long SetCameraTarget( const navlib::point_t& aPosition ) override;
|
||||
|
||||
long GetFrontView( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override;
|
||||
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override;
|
||||
|
||||
private:
|
||||
EDA_3D_CANVAS* m_canvas;
|
||||
TRACK_BALL* m_camera;
|
||||
bool m_capIsMoving;
|
||||
double m_newWidth;
|
||||
SFVEC3F m_rayOrigin;
|
||||
SFVEC3F m_rayDirection;
|
||||
|
||||
// The cached CAMERA affine matrix. This is used to determine if the camera has been
|
||||
// moved. The camera matrix is the world to camera affine.
|
||||
mutable glm::mat4 m_cameraMatrix;
|
||||
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_NL_3DVIEWER_PLUGIN". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
#endif // NL_3D_VIEWER_PLUGIN_IMPL_H_
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Jean-Pierre Charras, jp.charras@wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file 3d_read_mesh.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <macros.h>
|
||||
#include <kicad_string.h>
|
||||
#include <appl_wxstruct.h>
|
||||
|
||||
#include <3d_viewer.h>
|
||||
#include <info3d_visu.h>
|
||||
#include "3d_struct.h"
|
||||
#include "modelparsers.h"
|
||||
|
||||
// Imported function:
|
||||
extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
|
||||
|
||||
|
||||
S3D_MODEL_PARSER* S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
|
||||
const wxString aExtension )
|
||||
{
|
||||
if ( aExtension == wxT( "x3d" ) )
|
||||
{
|
||||
return new X3D_MODEL_PARSER( aMaster );
|
||||
}
|
||||
else if ( aExtension == wxT( "wrl" ) )
|
||||
{
|
||||
return new VRML_MODEL_PARSER( aMaster );
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int S3D_MASTER::ReadData()
|
||||
{
|
||||
if( m_Shape3DName.IsEmpty() )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Expand any environment variables embedded in footprint's m_Shape3DName field.
|
||||
wxString filename = wxExpandEnvVars( m_Shape3DName );
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
filename.Replace( wxT( "/" ), wxT( "\\" ) );
|
||||
#else
|
||||
filename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
#endif
|
||||
|
||||
if( !wxFileName::FileExists( filename ) )
|
||||
{
|
||||
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
|
||||
GetChars( m_Shape3DName ),
|
||||
GetChars( filename )
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wxFileName fn( filename );
|
||||
|
||||
wxString extension = fn.GetExt();
|
||||
S3D_MODEL_PARSER* parser = S3D_MODEL_PARSER::Create( this, extension );
|
||||
|
||||
if( parser )
|
||||
{
|
||||
parser->Load( filename );
|
||||
delete parser;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug( wxT( "Unknown file type '%s'" ), GetChars( extension ) );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int STRUCT_3D_SHAPE::ReadData( FILE* file, int* LineNum )
|
||||
{
|
||||
char line[512];
|
||||
|
||||
while( GetLine( file, line, LineNum, 512 ) )
|
||||
{
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file buffers_debug.cpp
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#include "buffers_debug.h"
|
||||
#include <wx/image.h> // Used for save an image to disk
|
||||
|
||||
/**
|
||||
* @param aRGBpixelBuffer from the wxWidgets documentation
|
||||
* "The data given must have the size (width*height*3).
|
||||
* The data must have been allocated with malloc(), NOT with operator new."
|
||||
*/
|
||||
static void dbg_save_rgb_buffer( const wxString& aFileName, unsigned char *aRGBpixelBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize )
|
||||
{
|
||||
wxImage image( aXSize, aYSize );
|
||||
image.SetData( aRGBpixelBuffer );
|
||||
image = image.Mirror( false );
|
||||
image.SaveFile( aFileName + wxT( ".png" ), wxBITMAP_TYPE_PNG );
|
||||
image.Destroy();
|
||||
}
|
||||
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const unsigned char *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize )
|
||||
{
|
||||
const unsigned int wxh = aXSize * aYSize;
|
||||
|
||||
unsigned char *pixelbuffer = (unsigned char*) malloc( wxh * 3 );
|
||||
|
||||
for( unsigned int i = 0; i < wxh; ++i )
|
||||
{
|
||||
unsigned char v = aInBuffer[i];
|
||||
|
||||
// Set RGB value with all same values intensities
|
||||
pixelbuffer[i * 3 + 0] = v;
|
||||
pixelbuffer[i * 3 + 1] = v;
|
||||
pixelbuffer[i * 3 + 2] = v;
|
||||
}
|
||||
|
||||
dbg_save_rgb_buffer( aFileName, pixelbuffer, aXSize, aYSize );
|
||||
}
|
||||
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const float *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize )
|
||||
{
|
||||
const unsigned int wxh = aXSize * aYSize;
|
||||
|
||||
unsigned char *pixelbuffer = (unsigned char*) malloc( wxh * 3 );
|
||||
|
||||
for( unsigned int i = 0; i < wxh; ++i )
|
||||
{
|
||||
const unsigned char v = (unsigned char)glm::min( (int)(aInBuffer[i] * 255.0f), 255 );
|
||||
|
||||
// Set RGB value with all same values intensities
|
||||
pixelbuffer[i * 3 + 0] = v;
|
||||
pixelbuffer[i * 3 + 1] = v;
|
||||
pixelbuffer[i * 3 + 2] = v;
|
||||
}
|
||||
|
||||
dbg_save_rgb_buffer( aFileName, pixelbuffer, aXSize, aYSize );
|
||||
}
|
||||
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const SFVEC3F *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize )
|
||||
{
|
||||
const unsigned int wxh = aXSize * aYSize;
|
||||
|
||||
unsigned char *pixelbuffer = (unsigned char*) malloc( wxh * 3 );
|
||||
|
||||
for( unsigned int i = 0; i < wxh; ++i )
|
||||
{
|
||||
const SFVEC3F &v = aInBuffer[i];
|
||||
const unsigned int ix3 = i * 3;
|
||||
|
||||
// Set RGB value with all same values intensities
|
||||
pixelbuffer[ix3 + 0] = (unsigned char) glm::min( (int) ( v.r * 255.0f ), 255 );
|
||||
pixelbuffer[ix3 + 1] = (unsigned char) glm::min( (int) ( v.g * 255.0f ), 255 );
|
||||
pixelbuffer[ix3 + 2] = (unsigned char) glm::min( (int) ( v.b * 255.0f ), 255 );
|
||||
}
|
||||
|
||||
dbg_save_rgb_buffer( aFileName, pixelbuffer, aXSize, aYSize );
|
||||
}
|
||||
|
||||
|
||||
void DBG_SaveNormalsBuffer( const wxString& aFileName, const SFVEC3F *aInNormalsBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize )
|
||||
{
|
||||
const unsigned int wxh = aXSize * aYSize;
|
||||
|
||||
unsigned char *pixelbuffer = (unsigned char*) malloc( wxh * 3 );
|
||||
|
||||
for( unsigned int i = 0; i < wxh; ++i )
|
||||
{
|
||||
const SFVEC3F &v = aInNormalsBuffer[i];
|
||||
const unsigned int ix3 = i * 3;
|
||||
|
||||
// Set RGB value with all same values intensities
|
||||
pixelbuffer[ix3 + 0] = (unsigned char) glm::min( (int) ( ( v.r + 1.0f ) * 127.0f ), 255 );
|
||||
pixelbuffer[ix3 + 1] = (unsigned char) glm::min( (int) ( ( v.g + 1.0f ) * 127.0f ), 255 );
|
||||
pixelbuffer[ix3 + 2] = (unsigned char) glm::min( (int) ( ( v.b + 1.0f ) * 127.0f ), 255 );
|
||||
}
|
||||
|
||||
dbg_save_rgb_buffer( aFileName, pixelbuffer, aXSize, aYSize );
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file buffers_debug.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef BUFFER_DEBUG_H
|
||||
#define BUFFER_DEBUG_H
|
||||
|
||||
#include <plugins/3dapi/xv3d_types.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const unsigned char *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize );
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const float *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize );
|
||||
|
||||
void DBG_SaveBuffer( const wxString& aFileName, const SFVEC3F *aInBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize );
|
||||
|
||||
void DBG_SaveNormalsBuffer( const wxString& aFileName, const SFVEC3F *aInNormalsBuffer,
|
||||
unsigned int aXSize, unsigned int aYSize );
|
||||
|
||||
#endif // BUFFER_DEBUG_H
|
||||
@@ -1,669 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file camera.cpp
|
||||
*/
|
||||
|
||||
#include "camera.h"
|
||||
#include <wx/log.h>
|
||||
#include <algorithm>
|
||||
|
||||
// A helper function to normalize aAngle between -2PI and +2PI
|
||||
inline void normalise2PI( float& aAngle )
|
||||
{
|
||||
while( aAngle > 0.0 )
|
||||
aAngle -= static_cast<float>( M_PI * 2.0f );
|
||||
|
||||
while( aAngle < 0.0 )
|
||||
aAngle += static_cast<float>( M_PI * 2.0f );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar *CAMERA::m_logTrace = wxT( "KI_TRACE_CAMERA" );
|
||||
|
||||
const float CAMERA::DEFAULT_MIN_ZOOM = 0.020f;
|
||||
const float CAMERA::DEFAULT_MAX_ZOOM = 2.0f;
|
||||
|
||||
|
||||
CAMERA::CAMERA( float aInitialDistance )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "CAMERA::CAMERA" ) );
|
||||
|
||||
m_camera_pos_init = SFVEC3F( 0.0f, 0.0f, -aInitialDistance );
|
||||
m_board_lookat_pos_init = SFVEC3F( 0.0f );
|
||||
m_windowSize = SFVEC2I( 0, 0 );
|
||||
m_projectionType = PROJECTION_TYPE::PERSPECTIVE;
|
||||
m_interpolation_mode = CAMERA_INTERPOLATION::BEZIER;
|
||||
|
||||
m_minZoom = DEFAULT_MIN_ZOOM;
|
||||
m_maxZoom = DEFAULT_MAX_ZOOM;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::Reset()
|
||||
{
|
||||
m_parametersChanged = true;
|
||||
m_projectionMatrix = glm::mat4( 1.0f );
|
||||
m_projectionMatrixInv = glm::mat4( 1.0f );
|
||||
m_rotationMatrix = glm::mat4( 1.0f );
|
||||
m_rotationMatrixAux = glm::mat4( 1.0f );
|
||||
m_lastPosition = wxPoint( 0, 0 );
|
||||
|
||||
m_zoom = 1.0f;
|
||||
m_zoom_t0 = 1.0f;
|
||||
m_zoom_t1 = 1.0f;
|
||||
m_camera_pos = m_camera_pos_init;
|
||||
m_camera_pos_t0 = m_camera_pos_init;
|
||||
m_camera_pos_t1 = m_camera_pos_init;
|
||||
m_lookat_pos = m_board_lookat_pos_init;
|
||||
m_lookat_pos_t0 = m_board_lookat_pos_init;
|
||||
m_lookat_pos_t1 = m_board_lookat_pos_init;
|
||||
|
||||
m_rotate_aux = SFVEC3F( 0.0f );
|
||||
m_rotate_aux_t0 = SFVEC3F( 0.0f );
|
||||
m_rotate_aux_t1 = SFVEC3F( 0.0f );
|
||||
|
||||
updateRotationMatrix();
|
||||
updateViewMatrix();
|
||||
m_viewMatrixInverse = glm::inverse( m_viewMatrix );
|
||||
m_scr_nX.clear();
|
||||
m_scr_nY.clear();
|
||||
rebuildProjection();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::Reset_T1()
|
||||
{
|
||||
m_camera_pos_t1 = m_camera_pos_init;
|
||||
m_zoom_t1 = 1.0f;
|
||||
m_rotate_aux_t1 = SFVEC3F( 0.0f );
|
||||
m_lookat_pos_t1 = m_board_lookat_pos_init;
|
||||
|
||||
// Since 0 = 2pi, we want to reset the angle to be the closest
|
||||
// one to where we currently are. That ensures that we rotate
|
||||
// the board around the smallest distance getting there.
|
||||
if( m_rotate_aux_t0.x > M_PI )
|
||||
m_rotate_aux_t1.x = static_cast<float>( 2.0f * M_PI );
|
||||
|
||||
if( m_rotate_aux_t0.y > M_PI )
|
||||
m_rotate_aux_t1.y = static_cast<float>( 2.0f * M_PI );
|
||||
|
||||
if( m_rotate_aux_t0.z > M_PI )
|
||||
m_rotate_aux_t1.z = static_cast<float>( 2.0f * M_PI );
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::SetBoardLookAtPos( const SFVEC3F& aBoardPos )
|
||||
{
|
||||
if( m_board_lookat_pos_init != aBoardPos )
|
||||
{
|
||||
m_board_lookat_pos_init = aBoardPos;
|
||||
m_lookat_pos = aBoardPos;
|
||||
|
||||
m_parametersChanged = true;
|
||||
|
||||
updateViewMatrix();
|
||||
updateFrustum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::zoomChanged()
|
||||
{
|
||||
if( m_zoom < m_minZoom )
|
||||
m_zoom = m_minZoom;
|
||||
|
||||
if( m_zoom > m_maxZoom )
|
||||
m_zoom = m_maxZoom;
|
||||
|
||||
m_camera_pos.z = m_camera_pos_init.z * m_zoom;
|
||||
|
||||
updateViewMatrix();
|
||||
rebuildProjection();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::updateViewMatrix()
|
||||
{
|
||||
m_viewMatrix = glm::translate( glm::mat4( 1.0f ), m_camera_pos ) *
|
||||
m_rotationMatrix * m_rotationMatrixAux *
|
||||
glm::translate( glm::mat4( 1.0f ), -m_lookat_pos );
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::updateRotationMatrix()
|
||||
{
|
||||
m_rotationMatrixAux = glm::rotate( glm::mat4( 1.0f ), m_rotate_aux.x,
|
||||
SFVEC3F( 1.0f, 0.0f, 0.0f ) );
|
||||
normalise2PI( m_rotate_aux.x );
|
||||
|
||||
m_rotationMatrixAux = glm::rotate( m_rotationMatrixAux, m_rotate_aux.y,
|
||||
SFVEC3F( 0.0f, 1.0f, 0.0f ) );
|
||||
normalise2PI( m_rotate_aux.y );
|
||||
|
||||
m_rotationMatrixAux = glm::rotate( m_rotationMatrixAux, m_rotate_aux.z,
|
||||
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
||||
normalise2PI( m_rotate_aux.z );
|
||||
|
||||
m_parametersChanged = true;
|
||||
|
||||
updateViewMatrix();
|
||||
updateFrustum();
|
||||
}
|
||||
|
||||
|
||||
glm::mat4 CAMERA::GetRotationMatrix() const
|
||||
{
|
||||
return m_rotationMatrix * m_rotationMatrixAux;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::SetRotationMatrix( const glm::mat4& aRotation )
|
||||
{
|
||||
m_parametersChanged = true;
|
||||
std::copy_n( glm::value_ptr( aRotation * glm::inverse( m_rotationMatrixAux ) ), 12,
|
||||
glm::value_ptr( m_rotationMatrix ) );
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::rebuildProjection()
|
||||
{
|
||||
if( ( m_windowSize.x == 0 ) || ( m_windowSize.y == 0 ) )
|
||||
return;
|
||||
|
||||
m_frustum.ratio = (float) m_windowSize.x / (float)m_windowSize.y;
|
||||
m_frustum.farD = glm::length( m_camera_pos_init ) * m_maxZoom * 2.0f;
|
||||
|
||||
switch( m_projectionType )
|
||||
{
|
||||
default:
|
||||
case PROJECTION_TYPE::PERSPECTIVE:
|
||||
|
||||
m_frustum.nearD = 0.10f;
|
||||
|
||||
m_frustum.angle = 45.0f;
|
||||
|
||||
m_projectionMatrix = glm::perspective( glm::radians( m_frustum.angle ), m_frustum.ratio,
|
||||
m_frustum.nearD, m_frustum.farD );
|
||||
|
||||
m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
|
||||
|
||||
m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f );
|
||||
|
||||
m_focalLen.x = ( (float)m_windowSize.y / (float)m_windowSize.x ) / m_frustum.tang;
|
||||
m_focalLen.y = 1.0f / m_frustum.tang;
|
||||
|
||||
m_frustum.nh = 2.0f * m_frustum.nearD * m_frustum.tang;
|
||||
m_frustum.nw = m_frustum.nh * m_frustum.ratio;
|
||||
m_frustum.fh = 2.0f * m_frustum.farD * m_frustum.tang;
|
||||
m_frustum.fw = m_frustum.fh * m_frustum.ratio;
|
||||
break;
|
||||
|
||||
case PROJECTION_TYPE::ORTHO:
|
||||
|
||||
// Keep the viewed plane at (m_camera_pos_init * m_zoom) the same dimensions in both projections.
|
||||
m_frustum.angle = 45.0f;
|
||||
m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f );
|
||||
|
||||
m_frustum.nearD = -m_frustum.farD; // Use a symmetrical clip plane for ortho projection
|
||||
|
||||
const float orthoReductionFactor =
|
||||
glm::length( m_camera_pos_init ) * m_zoom * m_frustum.tang;
|
||||
|
||||
// Initialize Projection Matrix for Orthographic View
|
||||
m_projectionMatrix = glm::ortho( -m_frustum.ratio * orthoReductionFactor,
|
||||
m_frustum.ratio * orthoReductionFactor,
|
||||
-orthoReductionFactor,
|
||||
orthoReductionFactor,
|
||||
m_frustum.nearD, m_frustum.farD );
|
||||
|
||||
m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
|
||||
|
||||
m_frustum.nw = orthoReductionFactor * 2.0f * m_frustum.ratio;
|
||||
m_frustum.nh = orthoReductionFactor * 2.0f;
|
||||
m_frustum.fw = m_frustum.nw;
|
||||
m_frustum.fh = m_frustum.nh;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if( ( m_windowSize.x > 0 ) && ( m_windowSize.y > 0 ) )
|
||||
{
|
||||
m_scr_nX.resize( m_windowSize.x + 1 );
|
||||
m_scr_nY.resize( m_windowSize.y + 1 );
|
||||
|
||||
// Precalc X values for camera -> ray generation
|
||||
for( unsigned int x = 0; x < (unsigned int)m_windowSize.x + 1; ++x )
|
||||
{
|
||||
// Converts 0.0 .. 1.0
|
||||
const float xNormalizedDeviceCoordinates = ( ( (float)x + 0.5f ) /
|
||||
(m_windowSize.x - 0.0f) );
|
||||
|
||||
// Converts -1.0 .. 1.0
|
||||
m_scr_nX[x] = 2.0f * xNormalizedDeviceCoordinates - 1.0f;
|
||||
}
|
||||
|
||||
// Precalc Y values for camera -> ray generation
|
||||
for( unsigned int y = 0; y < (unsigned int)m_windowSize.y + 1 ; ++y )
|
||||
{
|
||||
// Converts 0.0 .. 1.0
|
||||
const float yNormalizedDeviceCoordinates = ( ( (float)y + 0.5f ) /
|
||||
(m_windowSize.y - 0.0f) );
|
||||
|
||||
// Converts -1.0 .. 1.0
|
||||
m_scr_nY[y] = 2.0f * yNormalizedDeviceCoordinates - 1.0f;
|
||||
}
|
||||
|
||||
updateFrustum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::updateFrustum()
|
||||
{
|
||||
// Update matrix and vectors
|
||||
m_viewMatrixInverse = glm::inverse( m_viewMatrix );
|
||||
|
||||
m_right = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
||||
glm::vec4( SFVEC3F( 1.0, 0.0, 0.0 ), 0.0 ) ) );
|
||||
|
||||
m_up = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
||||
glm::vec4( SFVEC3F( 0.0, 1.0, 0.0 ), 0.0 ) ) );
|
||||
|
||||
m_dir = glm::normalize( SFVEC3F( m_viewMatrixInverse *
|
||||
glm::vec4( SFVEC3F( 0.0, 0.0, 1.0 ), 0.0 ) ) );
|
||||
|
||||
m_pos = SFVEC3F( m_viewMatrixInverse * glm::vec4( SFVEC3F( 0.0, 0.0, 0.0 ), 1.0 ) );
|
||||
|
||||
/*
|
||||
* Frustum is a implementation based on a tutorial by
|
||||
* http://www.lighthouse3d.com/tutorials/view-frustum-culling/
|
||||
*/
|
||||
|
||||
const SFVEC3F half_right_nw = m_right * m_frustum.nw * 0.5f;
|
||||
const SFVEC3F half_right_fw = m_right * m_frustum.fw * 0.5f;
|
||||
const SFVEC3F half_up_nh = m_up * m_frustum.nh * 0.5f;
|
||||
const SFVEC3F half_up_fh = m_up * m_frustum.fh * 0.5f;
|
||||
|
||||
// compute the centers of the near and far planes
|
||||
m_frustum.nc = m_pos - m_dir * m_frustum.nearD;
|
||||
m_frustum.fc = m_pos - m_dir * m_frustum.farD;
|
||||
|
||||
// compute the 4 corners of the frustum on the near plane
|
||||
m_frustum.ntl = m_frustum.nc + half_up_nh - half_right_nw;
|
||||
m_frustum.ntr = m_frustum.nc + half_up_nh + half_right_nw;
|
||||
m_frustum.nbl = m_frustum.nc - half_up_nh - half_right_nw;
|
||||
m_frustum.nbr = m_frustum.nc - half_up_nh + half_right_nw;
|
||||
|
||||
// compute the 4 corners of the frustum on the far plane
|
||||
m_frustum.ftl = m_frustum.fc + half_up_fh - half_right_fw;
|
||||
m_frustum.ftr = m_frustum.fc + half_up_fh + half_right_fw;
|
||||
m_frustum.fbl = m_frustum.fc - half_up_fh - half_right_fw;
|
||||
m_frustum.fbr = m_frustum.fc - half_up_fh + half_right_fw;
|
||||
|
||||
if( ( m_windowSize.x > 0 ) && ( m_windowSize.y > 0 ) )
|
||||
{
|
||||
// Reserve size for precalc values
|
||||
m_right_nX.resize( m_windowSize.x + 1 );
|
||||
m_up_nY.resize( m_windowSize.y + 1 );
|
||||
|
||||
// Precalc X values for camera -> ray generation
|
||||
for( unsigned int x = 0; x < ( (unsigned int) m_windowSize.x + 1 ); ++x )
|
||||
m_right_nX[x] = half_right_nw * m_scr_nX[x];
|
||||
|
||||
// Precalc Y values for camera -> ray generation
|
||||
for( unsigned int y = 0; y < ( (unsigned int) m_windowSize.y + 1 ); ++y )
|
||||
m_up_nY[y] = half_up_nh * m_scr_nY[y];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::MakeRay( const SFVEC2I& aWindowPos, SFVEC3F& aOutOrigin,
|
||||
SFVEC3F& aOutDirection ) const
|
||||
{
|
||||
wxASSERT( aWindowPos.x < m_windowSize.x );
|
||||
wxASSERT( aWindowPos.y < m_windowSize.y );
|
||||
|
||||
aOutOrigin = m_frustum.nc + m_up_nY[aWindowPos.y] + m_right_nX[aWindowPos.x];
|
||||
|
||||
switch( m_projectionType )
|
||||
{
|
||||
default:
|
||||
case PROJECTION_TYPE::PERSPECTIVE:
|
||||
aOutDirection = glm::normalize( aOutOrigin - m_pos );
|
||||
break;
|
||||
|
||||
case PROJECTION_TYPE::ORTHO:
|
||||
aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::MakeRay( const SFVEC2F& aWindowPos, SFVEC3F& aOutOrigin,
|
||||
SFVEC3F& aOutDirection ) const
|
||||
{
|
||||
wxASSERT( aWindowPos.x < (float)m_windowSize.x );
|
||||
wxASSERT( aWindowPos.y < (float)m_windowSize.y );
|
||||
|
||||
const SFVEC2F floorWinPos_f = glm::floor( aWindowPos );
|
||||
const SFVEC2I floorWinPos_i = (SFVEC2I)floorWinPos_f;
|
||||
const SFVEC2F relativeWinPos = aWindowPos - floorWinPos_f;
|
||||
|
||||
// Note: size of vectors m_up and m_right are m_windowSize + 1
|
||||
const SFVEC3F up_plus_right = m_up_nY[floorWinPos_i.y] * (1.0f - relativeWinPos.y) +
|
||||
m_up_nY[floorWinPos_i.y + 1] * relativeWinPos.y +
|
||||
m_right_nX[floorWinPos_i.x] * (1.0f - relativeWinPos.x) +
|
||||
m_right_nX[floorWinPos_i.x + 1] * relativeWinPos.x;
|
||||
|
||||
aOutOrigin = up_plus_right + m_frustum.nc;
|
||||
|
||||
switch( m_projectionType )
|
||||
{
|
||||
default:
|
||||
case PROJECTION_TYPE::PERSPECTIVE:
|
||||
aOutDirection = glm::normalize( aOutOrigin - m_pos );
|
||||
break;
|
||||
|
||||
case PROJECTION_TYPE::ORTHO:
|
||||
aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::MakeRayAtCurrentMousePosition( SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const
|
||||
{
|
||||
const SFVEC2I windowPos = SFVEC2I( m_lastPosition.x, m_windowSize.y - m_lastPosition.y );
|
||||
|
||||
if( ( 0 < windowPos.x ) && ( windowPos.x < m_windowSize.x ) &&
|
||||
( 0 < windowPos.y ) && ( windowPos.y < m_windowSize.y ) )
|
||||
{
|
||||
MakeRay( windowPos, aOutOrigin, aOutDirection );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const glm::mat4& CAMERA::GetProjectionMatrix() const
|
||||
{
|
||||
return m_projectionMatrix;
|
||||
}
|
||||
|
||||
|
||||
const glm::mat4& CAMERA::GetProjectionMatrixInv() const
|
||||
{
|
||||
return m_projectionMatrixInv;
|
||||
}
|
||||
|
||||
|
||||
float CAMERA::GetCameraMinDimension() const
|
||||
{
|
||||
return -m_camera_pos_init.z * m_frustum.tang;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::ResetXYpos()
|
||||
{
|
||||
m_parametersChanged = true;
|
||||
m_camera_pos.x = 0.0f;
|
||||
m_camera_pos.y = 0.0f;
|
||||
|
||||
updateViewMatrix();
|
||||
updateFrustum();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::ResetXYpos_T1()
|
||||
{
|
||||
m_camera_pos_t1.x = 0.0f;
|
||||
m_camera_pos_t1.y = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
const glm::mat4& CAMERA::GetViewMatrix() const
|
||||
{
|
||||
return m_viewMatrix;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::SetViewMatrix( glm::mat4 aViewMatrix )
|
||||
{
|
||||
SetRotationMatrix( aViewMatrix );
|
||||
|
||||
// The look at position in the view frame.
|
||||
glm::vec4 lookat = aViewMatrix * glm::vec4( m_lookat_pos, 1.0f );
|
||||
|
||||
wxLogTrace( m_logTrace,
|
||||
wxT( "CAMERA::SetViewMatrix aViewMatrix[3].z =%f, old_zoom=%f, new_zoom=%f, "
|
||||
"m[3].z=%f" ),
|
||||
aViewMatrix[3].z, m_zoom, lookat.z / m_camera_pos_init.z, lookat.z );
|
||||
|
||||
m_zoom = lookat.z / m_camera_pos_init.z;
|
||||
|
||||
if( m_zoom > m_maxZoom )
|
||||
{
|
||||
m_zoom = m_maxZoom;
|
||||
aViewMatrix[3].z += -lookat.z + m_maxZoom * m_camera_pos_init.z;
|
||||
}
|
||||
else if( m_zoom < m_minZoom )
|
||||
{
|
||||
m_zoom = m_minZoom;
|
||||
aViewMatrix[3].z += -lookat.z + m_minZoom * m_camera_pos_init.z;
|
||||
}
|
||||
|
||||
m_viewMatrix = std::move( aViewMatrix );
|
||||
m_camera_pos = m_viewMatrix
|
||||
* glm::inverse( m_rotationMatrix * m_rotationMatrixAux
|
||||
* glm::translate( glm::mat4( 1.0f ), -m_lookat_pos ) )[3];
|
||||
}
|
||||
|
||||
|
||||
const glm::mat4& CAMERA::GetViewMatrix_Inv() const
|
||||
{
|
||||
return m_viewMatrixInverse;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::SetCurMousePosition( const wxPoint& aNewMousePosition )
|
||||
{
|
||||
m_lastPosition = aNewMousePosition;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::ToggleProjection()
|
||||
{
|
||||
if( m_projectionType == PROJECTION_TYPE::ORTHO )
|
||||
m_projectionType = PROJECTION_TYPE::PERSPECTIVE;
|
||||
else
|
||||
m_projectionType = PROJECTION_TYPE::ORTHO;
|
||||
|
||||
rebuildProjection();
|
||||
}
|
||||
|
||||
|
||||
bool CAMERA::SetCurWindowSize( const wxSize& aSize )
|
||||
{
|
||||
const SFVEC2I newSize = SFVEC2I( aSize.x, aSize.y );
|
||||
|
||||
if( m_windowSize != newSize )
|
||||
{
|
||||
m_windowSize = newSize;
|
||||
rebuildProjection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::ZoomReset()
|
||||
{
|
||||
m_zoom = 1.0f;
|
||||
|
||||
m_camera_pos.z = m_camera_pos_init.z;
|
||||
|
||||
updateViewMatrix();
|
||||
rebuildProjection();
|
||||
}
|
||||
|
||||
|
||||
bool CAMERA::Zoom( float aFactor )
|
||||
{
|
||||
if( ( m_zoom <= m_minZoom && aFactor > 1 ) || ( m_zoom >= m_maxZoom && aFactor < 1 )
|
||||
|| aFactor == 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float zoom = m_zoom;
|
||||
m_zoom /= aFactor;
|
||||
|
||||
if( m_zoom <= m_minZoom && aFactor > 1 )
|
||||
{
|
||||
aFactor = zoom / m_minZoom;
|
||||
m_zoom = m_minZoom;
|
||||
}
|
||||
else if( m_zoom >= m_maxZoom && aFactor < 1 )
|
||||
{
|
||||
aFactor = zoom / m_maxZoom;
|
||||
m_zoom = m_maxZoom;
|
||||
}
|
||||
|
||||
m_camera_pos.z /= aFactor;
|
||||
|
||||
updateViewMatrix();
|
||||
rebuildProjection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CAMERA::Zoom_T1( float aFactor )
|
||||
{
|
||||
if( ( m_zoom <= m_minZoom && aFactor > 1 ) || ( m_zoom >= m_maxZoom && aFactor < 1 )
|
||||
|| aFactor == 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_zoom_t1 = m_zoom / aFactor;
|
||||
|
||||
if( m_zoom_t1 < m_minZoom )
|
||||
m_zoom_t1 = m_minZoom;
|
||||
|
||||
if( m_zoom_t1 > m_maxZoom )
|
||||
m_zoom_t1 = m_maxZoom;
|
||||
|
||||
m_camera_pos_t1.z = m_camera_pos_init.z * m_zoom_t1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateX( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux.x += aAngleInRadians;
|
||||
updateRotationMatrix();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateY( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux.y += aAngleInRadians;
|
||||
updateRotationMatrix();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateZ( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux.z += aAngleInRadians;
|
||||
updateRotationMatrix();
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateX_T1( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux_t1.x += aAngleInRadians;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateY_T1( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux_t1.y += aAngleInRadians;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::RotateZ_T1( float aAngleInRadians )
|
||||
{
|
||||
m_rotate_aux_t1.z += aAngleInRadians;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::SetT0_and_T1_current_T()
|
||||
{
|
||||
m_camera_pos_t0 = m_camera_pos;
|
||||
m_lookat_pos_t0 = m_lookat_pos;
|
||||
m_rotate_aux_t0 = m_rotate_aux;
|
||||
m_zoom_t0 = m_zoom;
|
||||
|
||||
m_camera_pos_t1 = m_camera_pos;
|
||||
m_lookat_pos_t1 = m_lookat_pos;
|
||||
m_rotate_aux_t1 = m_rotate_aux;
|
||||
m_zoom_t1 = m_zoom;
|
||||
}
|
||||
|
||||
|
||||
void CAMERA::Interpolate( float t )
|
||||
{
|
||||
wxASSERT( t >= 0.0f );
|
||||
|
||||
const float t0 = 1.0f - t;
|
||||
|
||||
m_camera_pos = m_camera_pos_t0 * t0 + m_camera_pos_t1 * t;
|
||||
m_lookat_pos = m_lookat_pos_t0 * t0 + m_lookat_pos_t1 * t;
|
||||
m_rotate_aux = m_rotate_aux_t0 * t0 + m_rotate_aux_t1 * t;
|
||||
m_zoom = m_zoom_t0 * t0 + m_zoom_t1 * t;
|
||||
|
||||
m_parametersChanged = true;
|
||||
|
||||
updateRotationMatrix();
|
||||
rebuildProjection();
|
||||
}
|
||||
|
||||
|
||||
bool CAMERA::ParametersChanged()
|
||||
{
|
||||
const bool parametersChanged = m_parametersChanged;
|
||||
|
||||
m_parametersChanged = false;
|
||||
|
||||
return parametersChanged;
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file camera.h
|
||||
* @brief Define an abstract camera.
|
||||
*/
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "../3d_rendering/raytracing/ray.h"
|
||||
#include <wx/gdicmn.h> // for wxSize
|
||||
#include <vector>
|
||||
|
||||
enum class PROJECTION_TYPE
|
||||
{
|
||||
ORTHO = 0,
|
||||
PERSPECTIVE
|
||||
};
|
||||
|
||||
/**
|
||||
* Frustum is a implementation based on a tutorial by
|
||||
* http://www.lighthouse3d.com/tutorials/view-frustum-culling/
|
||||
*/
|
||||
struct CAMERA_FRUSTUM
|
||||
{
|
||||
SFVEC3F nc;
|
||||
SFVEC3F fc;
|
||||
SFVEC3F ntl; ///< Near Top Left
|
||||
SFVEC3F ntr; ///< Near Top Right
|
||||
SFVEC3F nbl; ///< Near Bottom Left
|
||||
SFVEC3F nbr; ///< Near Bottom Right
|
||||
SFVEC3F ftl; ///< Far Top Left
|
||||
SFVEC3F ftr; ///< Far Top Right
|
||||
SFVEC3F fbl; ///< Far Bottom Left
|
||||
SFVEC3F fbr; ///< Far Bottom Right
|
||||
float nearD, farD, ratio, angle, tang;
|
||||
float nw, nh, fw, fh;
|
||||
};
|
||||
|
||||
|
||||
enum class CAMERA_INTERPOLATION
|
||||
{
|
||||
LINEAR,
|
||||
EASING_IN_OUT, // Quadratic
|
||||
BEZIER,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A class used to derive camera objects from.
|
||||
*
|
||||
* It must be derived by other classes to implement a real camera object.
|
||||
*/
|
||||
class CAMERA
|
||||
{
|
||||
public:
|
||||
static const float DEFAULT_MIN_ZOOM;
|
||||
static const float DEFAULT_MAX_ZOOM;
|
||||
|
||||
/**
|
||||
* Initialize a camera.
|
||||
*
|
||||
* @param aInitialDistance Initial Z-distance to the board
|
||||
*/
|
||||
explicit CAMERA( float aInitialDistance );
|
||||
|
||||
virtual ~CAMERA()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rotation matrix to be applied in a transformation camera.
|
||||
*
|
||||
* @return the rotation matrix of the camera
|
||||
*/
|
||||
glm::mat4 GetRotationMatrix() const;
|
||||
|
||||
const glm::mat4& GetViewMatrix() const;
|
||||
const glm::mat4& GetViewMatrix_Inv() const;
|
||||
|
||||
const glm::mat4& GetProjectionMatrix() const;
|
||||
const glm::mat4& GetProjectionMatrixInv() const;
|
||||
|
||||
const SFVEC3F& GetRight() const { return m_right; }
|
||||
const SFVEC3F& GetUp() const { return m_up; }
|
||||
const SFVEC3F& GetDir() const { return m_dir; }
|
||||
const SFVEC3F& GetPos() const { return m_pos; }
|
||||
const SFVEC2F& GetFocalLen() const { return m_focalLen; }
|
||||
float GetNear() const { return m_frustum.nearD; }
|
||||
float GetFar() const { return m_frustum.farD; }
|
||||
const CAMERA_FRUSTUM& GetFrustum() const { return m_frustum; }
|
||||
const SFVEC3F& GetLookAtPos() const { return m_lookat_pos; }
|
||||
|
||||
/**
|
||||
* Set the rotation matrix to be applied in a transformation camera, without
|
||||
* making any new calculations on camera.
|
||||
*
|
||||
* @param aRotation is the total rotation matrix of the camera.
|
||||
*/
|
||||
void SetRotationMatrix( const glm::mat4& aRotation );
|
||||
|
||||
/**
|
||||
* Set the affine matrix to be applied to a transformation camera.
|
||||
*
|
||||
* @param aViewMatrix is the affine matrix of the camera. The affine matrix
|
||||
* maps coordinates in the world frame to those in the
|
||||
* camera frame.
|
||||
*/
|
||||
void SetViewMatrix( glm::mat4 aViewMatrix );
|
||||
|
||||
void SetBoardLookAtPos( const SFVEC3F& aBoardPos );
|
||||
|
||||
void SetLookAtPos_T1( const SFVEC3F& aLookAtPos )
|
||||
{
|
||||
m_lookat_pos_t1 = aLookAtPos;
|
||||
}
|
||||
|
||||
const SFVEC3F& GetLookAtPos_T1() const { return m_lookat_pos_t1; }
|
||||
|
||||
const SFVEC3F& GetCameraPos() const { return m_camera_pos; }
|
||||
const SFVEC3F& GetCameraInitPos() const { return m_camera_pos_init; }
|
||||
|
||||
float GetCameraMinDimension() const;
|
||||
|
||||
/**
|
||||
* Calculate a new mouse drag position
|
||||
*/
|
||||
virtual void Drag( const wxPoint& aNewMousePosition ) = 0;
|
||||
|
||||
virtual void Pan( const wxPoint& aNewMousePosition ) = 0;
|
||||
|
||||
virtual void Pan( const SFVEC3F& aDeltaOffsetInc ) = 0;
|
||||
|
||||
virtual void Pan_T1( const SFVEC3F& aDeltaOffsetInc ) = 0;
|
||||
|
||||
/**
|
||||
* Reset the camera to initial state
|
||||
*/
|
||||
virtual void Reset();
|
||||
virtual void Reset_T1();
|
||||
|
||||
void ResetXYpos();
|
||||
void ResetXYpos_T1();
|
||||
|
||||
/**
|
||||
* Get the current mouse position.
|
||||
*/
|
||||
const wxPoint& GetCurMousePosition() { return m_lastPosition; }
|
||||
|
||||
/**
|
||||
* Update the current mouse position without make any new calculations on camera.
|
||||
*/
|
||||
void SetCurMousePosition( const wxPoint& aPosition );
|
||||
|
||||
void ToggleProjection();
|
||||
PROJECTION_TYPE GetProjection() { return m_projectionType; }
|
||||
void SetProjection( PROJECTION_TYPE aProjection ) { m_projectionType = aProjection; }
|
||||
|
||||
/**
|
||||
* Update the windows size of the camera.
|
||||
*
|
||||
* @return true if the windows size changed since last time.
|
||||
*/
|
||||
bool SetCurWindowSize( const wxSize& aSize );
|
||||
|
||||
void ZoomReset();
|
||||
|
||||
bool Zoom( float aFactor );
|
||||
|
||||
bool Zoom_T1( float aFactor );
|
||||
|
||||
float GetZoom() const { return m_zoom; }
|
||||
|
||||
float GetMinZoom() { return m_minZoom; }
|
||||
void SetMinZoom( float minZoom )
|
||||
{
|
||||
m_minZoom = minZoom;
|
||||
zoomChanged();
|
||||
}
|
||||
|
||||
float GetMaxZoom() { return m_maxZoom; }
|
||||
void SetMaxZoom( float maxZoom )
|
||||
{
|
||||
m_maxZoom = maxZoom;
|
||||
zoomChanged();
|
||||
}
|
||||
|
||||
void RotateX( float aAngleInRadians );
|
||||
void RotateY( float aAngleInRadians );
|
||||
void RotateZ( float aAngleInRadians );
|
||||
|
||||
void RotateX_T1( float aAngleInRadians );
|
||||
void RotateY_T1( float aAngleInRadians );
|
||||
void RotateZ_T1( float aAngleInRadians );
|
||||
|
||||
/**
|
||||
* This will set T0 and T1 with the current values.
|
||||
*/
|
||||
virtual void SetT0_and_T1_current_T();
|
||||
|
||||
/**
|
||||
* It will update the matrix to interpolate between T0 and T1 values.
|
||||
*
|
||||
* @param t the interpolation time, between 0.0f and 1.0f (it will clamp if >1).
|
||||
*/
|
||||
virtual void Interpolate( float t );
|
||||
|
||||
void SetInterpolateMode( CAMERA_INTERPOLATION aInterpolateMode )
|
||||
{
|
||||
m_interpolation_mode = aInterpolateMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if some of the parameters in camera was changed, it will reset the flag.
|
||||
*/
|
||||
bool ParametersChanged();
|
||||
|
||||
/**
|
||||
* @return true if some of the parameters in camera was changed, it will NOT reset the flag.
|
||||
*/
|
||||
bool ParametersChangedQuery() const { return m_parametersChanged; }
|
||||
|
||||
/**
|
||||
* Make a ray based on a windows screen position.
|
||||
*
|
||||
* @param aWindowPos the windows buffer position.
|
||||
* @param aOutOrigin out origin position of the ray.
|
||||
* @param aOutDirection out direction
|
||||
*/
|
||||
void MakeRay( const SFVEC2I& aWindowPos, SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const;
|
||||
|
||||
/**
|
||||
* Make a ray based on a windows screen position, it will interpolate based on the
|
||||
* \a aWindowPos.
|
||||
*
|
||||
* @param aWindowPos the windows buffer position (float value).
|
||||
* @param aOutOrigin out origin position of the ray.
|
||||
* @param aOutDirection out direction.
|
||||
*/
|
||||
void MakeRay( const SFVEC2F& aWindowPos, SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const;
|
||||
|
||||
/**
|
||||
* Make a ray based on the latest mouse position.
|
||||
*
|
||||
* @param aOutOrigin out origin position of the ray.
|
||||
* @param aOutDirection out direction.
|
||||
*/
|
||||
void MakeRayAtCurrentMousePosition( SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const;
|
||||
|
||||
/**
|
||||
* Update the camera.
|
||||
*/
|
||||
void Update() { updateFrustum(); }
|
||||
|
||||
protected:
|
||||
void zoomChanged();
|
||||
void rebuildProjection();
|
||||
void updateFrustum();
|
||||
void updateViewMatrix();
|
||||
|
||||
void updateRotationMatrix();
|
||||
|
||||
/**
|
||||
* 3D zoom value -- Z-distance is scaled by it
|
||||
*/
|
||||
float m_zoom;
|
||||
float m_zoom_t0;
|
||||
float m_zoom_t1;
|
||||
|
||||
/**
|
||||
* Possible 3D zoom range
|
||||
*/
|
||||
float m_minZoom;
|
||||
float m_maxZoom;
|
||||
|
||||
/**
|
||||
* The window size that this camera is working.
|
||||
*/
|
||||
SFVEC2I m_windowSize;
|
||||
|
||||
/**
|
||||
* The last mouse position in the screen
|
||||
*/
|
||||
wxPoint m_lastPosition;
|
||||
|
||||
glm::mat4 m_rotationMatrix;
|
||||
glm::mat4 m_rotationMatrixAux;
|
||||
glm::mat4 m_viewMatrix;
|
||||
glm::mat4 m_viewMatrixInverse;
|
||||
glm::mat4 m_projectionMatrix;
|
||||
glm::mat4 m_projectionMatrixInv;
|
||||
PROJECTION_TYPE m_projectionType;
|
||||
|
||||
CAMERA_FRUSTUM m_frustum;
|
||||
|
||||
SFVEC3F m_right;
|
||||
SFVEC3F m_up;
|
||||
SFVEC3F m_dir;
|
||||
SFVEC3F m_pos;
|
||||
|
||||
SFVEC2F m_focalLen;
|
||||
|
||||
SFVEC3F m_camera_pos_init;
|
||||
SFVEC3F m_camera_pos;
|
||||
SFVEC3F m_camera_pos_t0;
|
||||
SFVEC3F m_camera_pos_t1;
|
||||
|
||||
SFVEC3F m_lookat_pos;
|
||||
SFVEC3F m_lookat_pos_t0;
|
||||
SFVEC3F m_lookat_pos_t1;
|
||||
SFVEC3F m_board_lookat_pos_init; ///< Default boardlookat position (the board center).
|
||||
|
||||
SFVEC3F m_rotate_aux; ///< Stores the rotation angle auxiliary.
|
||||
SFVEC3F m_rotate_aux_t0;
|
||||
SFVEC3F m_rotate_aux_t1;
|
||||
|
||||
CAMERA_INTERPOLATION m_interpolation_mode;
|
||||
|
||||
/**
|
||||
* Precalc values array used to calc ray for each pixel (constant for the same window size).
|
||||
*/
|
||||
std::vector< float > m_scr_nX;
|
||||
std::vector< float > m_scr_nY;
|
||||
|
||||
/**
|
||||
* Precalc values array used to calc ray for each pixel, for X and Y axis of each new
|
||||
* camera position.
|
||||
*/
|
||||
std::vector< SFVEC3F > m_right_nX;
|
||||
std::vector< SFVEC3F > m_up_nY;
|
||||
|
||||
/**
|
||||
* Set to true if any of the parameters in the camera was changed
|
||||
*/
|
||||
bool m_parametersChanged;
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
*
|
||||
* The debug output can be turned on by setting the WXTRACE environment variable to
|
||||
* "KI_TRACE_CAMERA". See the wxWidgets documentation on wxLogTrace for
|
||||
* more information.
|
||||
*/
|
||||
static const wxChar* m_logTrace;
|
||||
};
|
||||
|
||||
#endif // CAMERA_H
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file color_rgb.cpp
|
||||
*/
|
||||
|
||||
|
||||
#include "color_rgb.h"
|
||||
|
||||
|
||||
COLOR_RGB::COLOR_RGB( const SFVEC3F& aColor )
|
||||
{
|
||||
r = (unsigned int) glm::clamp( (int) ( aColor.r * 255 ), 0, 255 );
|
||||
g = (unsigned int) glm::clamp( (int) ( aColor.g * 255 ), 0, 255 );
|
||||
b = (unsigned int) glm::clamp( (int) ( aColor.b * 255 ), 0, 255 );
|
||||
}
|
||||
|
||||
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2 )
|
||||
{
|
||||
const unsigned int r = aC1.r + aC2.r;
|
||||
const unsigned int g = aC1.g + aC2.g;
|
||||
const unsigned int b = aC1.b + aC2.b;
|
||||
|
||||
return COLOR_RGB( ( r >> 1 ), ( g >> 1 ), ( b >> 1 ) );
|
||||
}
|
||||
|
||||
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2, const COLOR_RGB& aC3 )
|
||||
{
|
||||
const unsigned int r = aC1.r + aC2.r + aC3.r;
|
||||
const unsigned int g = aC1.g + aC2.g + aC3.g;
|
||||
const unsigned int b = aC1.b + aC2.b + aC3.b;
|
||||
|
||||
return COLOR_RGB( ( r / 3 ), ( g / 3 ), ( b / 3 ) );
|
||||
}
|
||||
|
||||
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2, const COLOR_RGB& aC3,
|
||||
const COLOR_RGB& aC4 )
|
||||
{
|
||||
const unsigned int r = aC1.r + aC2.r + aC3.r + aC4.r;
|
||||
const unsigned int g = aC1.g + aC2.g + aC3.g + aC4.g;
|
||||
const unsigned int b = aC1.b + aC2.b + aC3.b + aC4.b;
|
||||
|
||||
return COLOR_RGB( ( r >> 2 ), ( g >> 2 ), ( b >> 2 ) );
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file color_rgb.h
|
||||
*/
|
||||
|
||||
#ifndef COLOR_RGB_H
|
||||
#define COLOR_RGB_H
|
||||
|
||||
#include <plugins/3dapi/xv3d_types.h>
|
||||
|
||||
union COLOR_RGB
|
||||
{
|
||||
unsigned char c[3];
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
};
|
||||
|
||||
COLOR_RGB( const SFVEC3F& aColor );
|
||||
COLOR_RGB() { r = 0; g = 0; b = 0; }
|
||||
COLOR_RGB( unsigned char aR, unsigned char aG, unsigned char aB )
|
||||
{
|
||||
r = aR;
|
||||
g = aG;
|
||||
b = aB;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2 );
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2, const COLOR_RGB& aC3 );
|
||||
COLOR_RGB BlendColor( const COLOR_RGB& aC1, const COLOR_RGB& aC2, const COLOR_RGB& aC3,
|
||||
const COLOR_RGB& aC4 );
|
||||
|
||||
#endif // COLOR_RGB_H
|
||||
@@ -1,600 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file image.cpp
|
||||
* @brief one 8bit-channel image implementation.
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
#include "buffers_debug.h"
|
||||
#include <cstring> // For memcpy
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP( n, min, max ) {if( n < min ) n=min; else if( n > max ) n = max;}
|
||||
#endif
|
||||
|
||||
|
||||
IMAGE::IMAGE( unsigned int aXsize, unsigned int aYsize )
|
||||
{
|
||||
m_wxh = aXsize * aYsize;
|
||||
m_pixels = new unsigned char[m_wxh];
|
||||
memset( m_pixels, 0, m_wxh );
|
||||
m_width = aXsize;
|
||||
m_height = aYsize;
|
||||
m_wraping = IMAGE_WRAP::CLAMP;
|
||||
}
|
||||
|
||||
|
||||
IMAGE::IMAGE( const IMAGE& aSrcImage )
|
||||
{
|
||||
m_wxh = aSrcImage.GetWidth() * aSrcImage.GetHeight();
|
||||
m_pixels = new unsigned char[m_wxh];
|
||||
memcpy( m_pixels, aSrcImage.GetBuffer(), m_wxh );
|
||||
m_width = aSrcImage.GetWidth();
|
||||
m_height = aSrcImage.GetHeight();
|
||||
m_wraping = IMAGE_WRAP::CLAMP;
|
||||
}
|
||||
|
||||
|
||||
IMAGE::~IMAGE()
|
||||
{
|
||||
delete[] m_pixels;
|
||||
}
|
||||
|
||||
|
||||
unsigned char* IMAGE::GetBuffer() const
|
||||
{
|
||||
return m_pixels;
|
||||
}
|
||||
|
||||
|
||||
bool IMAGE::wrapCoords( int* aXo, int* aYo ) const
|
||||
{
|
||||
int x = *aXo;
|
||||
int y = *aYo;
|
||||
|
||||
switch( m_wraping )
|
||||
{
|
||||
case IMAGE_WRAP::CLAMP:
|
||||
x = ( x < 0 ) ? 0 : x;
|
||||
x = ( x >= (int) ( m_width - 1 ) ) ? ( m_width - 1 ) : x;
|
||||
y = ( y < 0 ) ? 0 : y;
|
||||
y = ( y >= (int) ( m_height - 1 ) ) ? ( m_height - 1 ) : y;
|
||||
break;
|
||||
|
||||
case IMAGE_WRAP::WRAP:
|
||||
x = ( x < 0 ) ? ( ( m_width - 1 ) + x ) : x;
|
||||
x = ( x >= (int) ( m_width - 1 ) ) ? ( x - m_width ) : x;
|
||||
y = ( y < 0 ) ? ( ( m_height - 1 ) + y ) : y;
|
||||
y = ( y >= (int) ( m_height - 1 ) ) ? ( y - m_height ) : y;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( ( x < 0 ) || ( x >= (int) m_width ) || ( y < 0 ) || ( y >= (int) m_height ) )
|
||||
return false;
|
||||
|
||||
*aXo = x;
|
||||
*aYo = y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::plot8CircleLines( int aCx, int aCy, int aX, int aY, unsigned char aValue )
|
||||
{
|
||||
Hline( aCx - aX, aCx + aX, aCy + aY, aValue );
|
||||
Hline( aCx - aX, aCx + aX, aCy - aY, aValue );
|
||||
Hline( aCx - aY, aCx + aY, aCy + aX, aValue );
|
||||
Hline( aCx - aY, aCx + aY, aCy - aX, aValue );
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::Setpixel( int aX, int aY, unsigned char aValue )
|
||||
{
|
||||
if( wrapCoords( &aX, &aY ) )
|
||||
m_pixels[aX + aY * m_width] = aValue;
|
||||
}
|
||||
|
||||
|
||||
unsigned char IMAGE::Getpixel( int aX, int aY ) const
|
||||
{
|
||||
if( wrapCoords( &aX, &aY ) )
|
||||
return m_pixels[aX + aY * m_width];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::Hline( int aXStart, int aXEnd, int aY, unsigned char aValue )
|
||||
{
|
||||
if( ( aY < 0 ) || ( aY >= (int) m_height ) || ( ( aXStart < 0 ) && ( aXEnd < 0 ) )
|
||||
|| ( ( aXStart >= (int) m_width ) && ( aXEnd >= (int) m_width ) ) )
|
||||
return;
|
||||
|
||||
if( aXStart > aXEnd )
|
||||
{
|
||||
int swap = aXStart;
|
||||
|
||||
aXStart = aXEnd;
|
||||
aXEnd = swap;
|
||||
}
|
||||
|
||||
// Clamp line
|
||||
if( aXStart < 0 )
|
||||
aXStart = 0;
|
||||
|
||||
if( aXEnd >= (int)m_width )
|
||||
aXEnd = m_width - 1;
|
||||
|
||||
unsigned char* pixelPtr = &m_pixels[aXStart + aY * m_width];
|
||||
unsigned char* pixelPtrEnd = pixelPtr + (unsigned int) ( ( aXEnd - aXStart ) + 1 );
|
||||
|
||||
while( pixelPtr < pixelPtrEnd )
|
||||
{
|
||||
*pixelPtr = aValue;
|
||||
pixelPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Based on paper
|
||||
// http://web.engr.oregonstate.edu/~sllu/bcircle.pdf
|
||||
void IMAGE::CircleFilled( int aCx, int aCy, int aRadius, unsigned char aValue )
|
||||
{
|
||||
int x = aRadius;
|
||||
int y = 0;
|
||||
int xChange = 1 - 2 * aRadius;
|
||||
int yChange = 0;
|
||||
int radiusError = 0;
|
||||
|
||||
while( x >= y )
|
||||
{
|
||||
plot8CircleLines( aCx, aCy, x, y, aValue );
|
||||
y++;
|
||||
radiusError += yChange;
|
||||
yChange += 2;
|
||||
|
||||
if( ( 2 * radiusError + xChange ) > 0 )
|
||||
{
|
||||
x--;
|
||||
radiusError += xChange;
|
||||
xChange += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::Invert()
|
||||
{
|
||||
for( unsigned int it = 0; it < m_wxh; it++ )
|
||||
m_pixels[it] = 255 - m_pixels[it];
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::CopyFull( const IMAGE* aImgA, const IMAGE* aImgB, IMAGE_OP aOperation )
|
||||
{
|
||||
int aV, bV;
|
||||
|
||||
if( aOperation == IMAGE_OP::RAW )
|
||||
{
|
||||
if( aImgA == nullptr )
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ( aImgA == nullptr ) || ( aImgB == nullptr ) )
|
||||
return;
|
||||
}
|
||||
|
||||
switch( aOperation )
|
||||
{
|
||||
case IMAGE_OP::RAW:
|
||||
memcpy( m_pixels, aImgA->m_pixels, m_wxh );
|
||||
break;
|
||||
|
||||
case IMAGE_OP::ADD:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
aV = (aV + bV);
|
||||
aV = (aV > 255)?255:aV;
|
||||
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::SUB:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
aV = (aV - bV);
|
||||
aV = (aV < 0)?0:aV;
|
||||
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::DIF:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = abs( aV - bV );
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::MUL:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] =
|
||||
(unsigned char) ( ( ( (float) aV / 255.0f ) * ( (float) bV / 255.0f ) ) * 255 );
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::AND:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] & aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::OR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] | aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::XOR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] ^ aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::BLEND50:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = (aV + bV) / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::MIN:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = (aV < bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_OP::MAX:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = (aV > bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TIP: If you want create or test filters you can use GIMP
|
||||
// with a generic convolution matrix and get the values from there.
|
||||
// http://docs.gimp.org/nl/plug-in-convmatrix.html
|
||||
// clang-format off
|
||||
static const S_FILTER FILTERS[] = {
|
||||
// IMAGE_FILTER::HIPASS
|
||||
{
|
||||
{ { 0, -1, -1, -1, 0},
|
||||
{-1, 2, -4, 2, -1},
|
||||
{-1, -4, 13, -4, -1},
|
||||
{-1, 2, -4, 2, -1},
|
||||
{ 0, -1, -1, -1, 0}
|
||||
},
|
||||
7,
|
||||
255
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::GAUSSIAN_BLUR
|
||||
{
|
||||
{ { 3, 5, 7, 5, 3},
|
||||
{ 5, 9, 12, 9, 5},
|
||||
{ 7, 12, 20, 12, 7},
|
||||
{ 5, 9, 12, 9, 5},
|
||||
{ 3, 5, 7, 5, 3}
|
||||
},
|
||||
182,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::GAUSSIAN_BLUR2
|
||||
{
|
||||
{ { 1, 4, 7, 4, 1},
|
||||
{ 4, 16, 26, 16, 4},
|
||||
{ 7, 26, 41, 26, 7},
|
||||
{ 4, 16, 26, 16, 4},
|
||||
{ 1, 4, 7, 4, 1}
|
||||
},
|
||||
273,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::INVERT_BLUR
|
||||
{
|
||||
{ { 0, 0, 0, 0, 0},
|
||||
{ 0, 0, -1, 0, 0},
|
||||
{ 0, -1, 0, -1, 0},
|
||||
{ 0, 0, -1, 0, 0},
|
||||
{ 0, 0, 0, 0, 0}
|
||||
},
|
||||
4,
|
||||
255
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::CARTOON
|
||||
{
|
||||
{ {-1, -1, -1, -1, 0},
|
||||
{-1, 0, 0, 0, 0},
|
||||
{-1, 0, 4, 0, 0},
|
||||
{ 0, 0, 0, 1, 0},
|
||||
{ 0, 0, 0, 0, 4}
|
||||
},
|
||||
3,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::EMBOSS
|
||||
{
|
||||
{ {-1, -1, -1, -1, 0},
|
||||
{-1, -1, -1, 0, 1},
|
||||
{-1, -1, 0, 1, 1},
|
||||
{-1, 0, 1, 1, 1},
|
||||
{ 0, 1, 1, 1, 1}
|
||||
},
|
||||
1,
|
||||
128
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::SHARPEN
|
||||
{
|
||||
{ {-1, -1, -1, -1, -1},
|
||||
{-1, 2, 2, 2, -1},
|
||||
{-1, 2, 8, 2, -1},
|
||||
{-1, 2, 2, 2, -1},
|
||||
{-1, -1, -1, -1, -1}
|
||||
},
|
||||
8,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::MELT
|
||||
{
|
||||
{ { 4, 2, 6, 8, 1},
|
||||
{ 1, 2, 5, 4, 2},
|
||||
{ 0, -1, 1, -1, 0},
|
||||
{ 0, 0, -2, 0, 0},
|
||||
{ 0, 0, 0, 0, 0}
|
||||
},
|
||||
32,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::SOBEL_GX
|
||||
{
|
||||
{ { 0, 0, 0, 0, 0},
|
||||
{ 0, -1, 0, 1, 0},
|
||||
{ 0, -2, 0, 2, 0},
|
||||
{ 0, -1, 0, 1, 0},
|
||||
{ 0, 0, 0, 0, 0}
|
||||
},
|
||||
1,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::SOBEL_GY
|
||||
{
|
||||
{ { 1, 2, 4, 2, 1},
|
||||
{-1, -1, 0, 1, 1},
|
||||
{-2, -2, 0, 2, 2},
|
||||
{-1, -1, 0, 1, 1},
|
||||
{-1, -2, -4, -2, -1},
|
||||
},
|
||||
1,
|
||||
0
|
||||
},
|
||||
|
||||
// IMAGE_FILTER::BLUR_3X3
|
||||
{
|
||||
{ { 0, 0, 0, 0, 0},
|
||||
{ 0, 1, 2, 1, 0},
|
||||
{ 0, 2, 4, 2, 0},
|
||||
{ 0, 1, 2, 1, 0},
|
||||
{ 0, 0, 0, 0, 0},
|
||||
},
|
||||
16,
|
||||
0
|
||||
}
|
||||
};// Filters
|
||||
// clang-format on
|
||||
|
||||
|
||||
/// @todo: This function can be optimized slipping it between the edges and
|
||||
/// do it without use the getpixel function.
|
||||
/// Optimization can be done to m_pixels[ix + iy * m_width]
|
||||
/// but keep in mind the parallel process of the algorithm
|
||||
void IMAGE::EfxFilter( IMAGE* aInImg, IMAGE_FILTER aFilterType )
|
||||
{
|
||||
S_FILTER filter = FILTERS[static_cast<int>( aFilterType )];
|
||||
|
||||
aInImg->m_wraping = IMAGE_WRAP::CLAMP;
|
||||
m_wraping = IMAGE_WRAP::CLAMP;
|
||||
|
||||
std::atomic<size_t> nextRow( 0 );
|
||||
std::atomic<size_t> threadsFinished( 0 );
|
||||
|
||||
size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
|
||||
|
||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||
{
|
||||
std::thread t = std::thread( [&]()
|
||||
{
|
||||
for( size_t iy = nextRow.fetch_add( 1 ); iy < m_height; iy = nextRow.fetch_add( 1 ) )
|
||||
{
|
||||
for( size_t ix = 0; ix < m_width; ix++ )
|
||||
{
|
||||
int v = 0;
|
||||
|
||||
for( size_t sy = 0; sy < 5; sy++ )
|
||||
{
|
||||
for( size_t sx = 0; sx < 5; sx++ )
|
||||
{
|
||||
int factor = filter.kernel[sx][sy];
|
||||
unsigned char pixelv = aInImg->Getpixel( ix + sx - 2, iy + sy - 2 );
|
||||
|
||||
v += pixelv * factor;
|
||||
}
|
||||
}
|
||||
|
||||
v /= filter.div;
|
||||
v += filter.offset;
|
||||
CLAMP(v, 0, 255);
|
||||
|
||||
/// @todo This needs to write to a separate buffer.
|
||||
m_pixels[ix + iy * m_width] = v;
|
||||
}
|
||||
}
|
||||
|
||||
threadsFinished++;
|
||||
} );
|
||||
|
||||
t.detach();
|
||||
}
|
||||
|
||||
while( threadsFinished < parallelThreadCount )
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::EfxFilter_SkipCenter( IMAGE* aInImg, IMAGE_FILTER aFilterType, unsigned int aRadius )
|
||||
{
|
||||
if( ( !aInImg ) || ( m_width != aInImg->m_width ) || ( m_height != aInImg->m_height ) )
|
||||
return;
|
||||
|
||||
S_FILTER filter = FILTERS[static_cast<int>( aFilterType )];
|
||||
|
||||
aInImg->m_wraping = IMAGE_WRAP::ZERO;
|
||||
|
||||
const unsigned int radiusSquared = aRadius * aRadius;
|
||||
|
||||
const unsigned int xCenter = m_width / 2;
|
||||
const unsigned int yCenter = m_height / 2;
|
||||
|
||||
for( size_t iy = 0; iy < m_height; iy++ )
|
||||
{
|
||||
int yc = iy - yCenter;
|
||||
|
||||
unsigned int ycsq = yc * yc;
|
||||
|
||||
for( size_t ix = 0; ix < m_width; ix++ )
|
||||
{
|
||||
int xc = ix - xCenter;
|
||||
|
||||
unsigned int xcsq = xc * xc;
|
||||
|
||||
if( ( xcsq + ycsq ) < radiusSquared )
|
||||
{
|
||||
const unsigned int offset = ix + iy * m_width;
|
||||
|
||||
m_pixels[offset] = aInImg->m_pixels[offset];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
|
||||
for( size_t sy = 0; sy < 5; sy++ )
|
||||
{
|
||||
for( size_t sx = 0; sx < 5; sx++ )
|
||||
{
|
||||
int factor = filter.kernel[sx][sy];
|
||||
unsigned char pixelv = aInImg->Getpixel( ix + sx - 2, iy + sy - 2 );
|
||||
|
||||
v += pixelv * factor;
|
||||
}
|
||||
}
|
||||
|
||||
v /= filter.div;
|
||||
v += filter.offset;
|
||||
CLAMP(v, 0, 255);
|
||||
|
||||
m_pixels[ix + iy * m_width] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::SetPixelsFromNormalizedFloat( const float* aNormalizedFloatArray )
|
||||
{
|
||||
for( unsigned int i = 0; i < m_wxh; i++ )
|
||||
{
|
||||
int v = aNormalizedFloatArray[i] * 255;
|
||||
|
||||
CLAMP( v, 0, 255 );
|
||||
m_pixels[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IMAGE::SaveAsPNG( const wxString& aFileName ) const
|
||||
{
|
||||
DBG_SaveBuffer( aFileName, m_pixels, m_width, m_height );
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file image.h
|
||||
* @brief one 8bit-channel image definition.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
/// Image operation type
|
||||
enum class IMAGE_OP
|
||||
{
|
||||
RAW,
|
||||
ADD,
|
||||
SUB,
|
||||
DIF,
|
||||
MUL,
|
||||
AND,
|
||||
OR,
|
||||
XOR,
|
||||
BLEND50,
|
||||
MIN,
|
||||
MAX
|
||||
};
|
||||
|
||||
|
||||
/// Image wrap type enumeration
|
||||
enum class IMAGE_WRAP
|
||||
{
|
||||
ZERO, ///< Coords that wraps are not evaluated
|
||||
CLAMP, ///< Coords are clamped to image size
|
||||
WRAP ///< Coords are wrapped around
|
||||
};
|
||||
|
||||
|
||||
/// Filter type enumeration
|
||||
enum class IMAGE_FILTER
|
||||
{
|
||||
HIPASS,
|
||||
GAUSSIAN_BLUR,
|
||||
GAUSSIAN_BLUR2,
|
||||
INVERT_BLUR,
|
||||
CARTOON,
|
||||
EMBOSS,
|
||||
SHARPEN,
|
||||
MELT,
|
||||
SOBEL_GX,
|
||||
SOBEL_GY,
|
||||
BLUR_3X3,
|
||||
};
|
||||
|
||||
/// 5x5 Filter struct parameters
|
||||
struct S_FILTER
|
||||
{
|
||||
signed char kernel[5][5];
|
||||
unsigned int div;
|
||||
unsigned char offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Manage an 8-bit channel image.
|
||||
*/
|
||||
class IMAGE
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a IMAGE based on image size.
|
||||
*
|
||||
* @param aXsize x size
|
||||
* @param aYsize y size
|
||||
*/
|
||||
IMAGE( unsigned int aXsize, unsigned int aYsize );
|
||||
|
||||
/**
|
||||
* Construct a IMAGE based from an existing image.
|
||||
*
|
||||
* It will make a copy the \a aSrcImage.
|
||||
*
|
||||
* @param aSrcImage
|
||||
*/
|
||||
IMAGE( const IMAGE& aSrcImage );
|
||||
|
||||
~IMAGE();
|
||||
|
||||
/**
|
||||
* Set a value in a pixel position, position is clamped in accordance with the
|
||||
* current clamp settings.
|
||||
*
|
||||
* @param aX x position
|
||||
* @param aY y position
|
||||
* @param aValue value to set the pixel
|
||||
*/
|
||||
void Setpixel( int aX, int aY, unsigned char aValue );
|
||||
|
||||
/**
|
||||
* Get the pixel value from pixel position, position is clamped in accord with the
|
||||
* current clamp settings.
|
||||
*
|
||||
* @param aX x position
|
||||
* @param aY y position
|
||||
* @return unsigned char - pixel value
|
||||
*/
|
||||
unsigned char Getpixel( int aX, int aY ) const;
|
||||
|
||||
/**
|
||||
* Draw a horizontal line.
|
||||
*
|
||||
* @param aXStart x start position
|
||||
* @param aXEnd x end position
|
||||
* @param aY y position
|
||||
* @param aValue value to add
|
||||
*/
|
||||
void Hline( int aXStart, int aXEnd, int aY, unsigned char aValue );
|
||||
|
||||
void CircleFilled( int aCx, int aCy, int aRadius, unsigned char aValue );
|
||||
|
||||
/**
|
||||
* Perform a copy operation based on \a aOperation type.
|
||||
*
|
||||
* The available image operations.
|
||||
* - IMAGE_OP::RAW this <- aImgA
|
||||
* - IMAGE_OP::ADD this <- CLAMP(aImgA + aImgB)
|
||||
* - IMAGE_OP::SUB this <- CLAMP(aImgA - aImgB)
|
||||
* - IMAGE_OP::DIF this <- abs(aImgA - aImgB)
|
||||
* - IMAGE_OP::MUL this <- aImgA * aImgB
|
||||
* - IMAGE_OP::AND this <- aImgA & aImgB
|
||||
* - IMAGE_OP::OR this <- aImgA | aImgB
|
||||
* - IMAGE_OP::XOR this <- aImgA ^ aImgB
|
||||
* - IMAGE_OP::BLEND50 this <- (aImgA + aImgB) / 2
|
||||
* - IMAGE_OP::MIN this <- (aImgA < aImgB) ? aImgA : aImgB
|
||||
* - IMAGE_OP::MAX this <- (aImgA > aImgB) ? aImgA : aImgB
|
||||
*
|
||||
* @param aImgA an image input.
|
||||
* @param aImgB an image input.
|
||||
* @param aOperation operation to perform
|
||||
*/
|
||||
void CopyFull( const IMAGE* aImgA, const IMAGE* aImgB, IMAGE_OP aOperation );
|
||||
|
||||
/**
|
||||
* Invert the values of this image <- (255 - this)
|
||||
*/
|
||||
void Invert();
|
||||
|
||||
/**
|
||||
* Apply a filter to the input image and store it in the image class.
|
||||
*
|
||||
* @param aInImg input image
|
||||
* @param aFilterType filter type to apply
|
||||
*/
|
||||
void EfxFilter( IMAGE* aInImg, IMAGE_FILTER aFilterType );
|
||||
|
||||
/**
|
||||
* Apply a filter to the input image and store it in the image class.
|
||||
* skip the circle center defined by radius
|
||||
*
|
||||
* @param aInImg input image
|
||||
* @param aFilterType filter type to apply
|
||||
* @param aRadius center circle that the effect will not be applied
|
||||
*/
|
||||
void EfxFilter_SkipCenter( IMAGE* aInImg, IMAGE_FILTER aFilterType, unsigned int aRadius );
|
||||
|
||||
/**
|
||||
* Save image buffer to a PNG file into the working folder.
|
||||
*
|
||||
* Each RGB channel will have the 8bit-channel from the image.
|
||||
*
|
||||
* @param aFileName file name (without extension)
|
||||
*/
|
||||
void SaveAsPNG( const wxString& aFileName ) const;
|
||||
|
||||
/**
|
||||
* Set the current channel from a float normalized (0.0 - 1.0) buffer.
|
||||
*
|
||||
* this <- CLAMP(NormalizedFloat * 255)
|
||||
*
|
||||
* @param aNormalizedFloatArray a float array with the same size of the image
|
||||
*/
|
||||
void SetPixelsFromNormalizedFloat( const float* aNormalizedFloatArray );
|
||||
|
||||
/**
|
||||
* Get the image buffer pointer.
|
||||
*
|
||||
* @return unsigned char* the pointer of the buffer 8bit channel.
|
||||
*/
|
||||
unsigned char* GetBuffer() const;
|
||||
|
||||
unsigned int GetWidth() const { return m_width; }
|
||||
unsigned int GetHeight() const { return m_height; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Calculate the coordinates points in accord with the current clamping settings.
|
||||
*
|
||||
* @param aXo X coordinate to be converted (output).
|
||||
* @param aXo Y coordinate to be converted (output).
|
||||
* @return bool - true if the coordinates are inside the image, false otherwise.
|
||||
*/
|
||||
bool wrapCoords( int* aXo, int* aYo ) const;
|
||||
|
||||
void plot8CircleLines( int aCx, int aCy, int aX, int aY, unsigned char aValue );
|
||||
|
||||
unsigned char* m_pixels; ///< buffer to store the image 8bit-channel
|
||||
unsigned int m_width; ///< width of the image
|
||||
unsigned int m_height; ///< height of the image
|
||||
unsigned int m_wxh; ///< width * height precalc value
|
||||
IMAGE_WRAP m_wraping; ///< current wrapping type
|
||||
};
|
||||
|
||||
#endif // IMAGE_H
|
||||
@@ -1,610 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_ogl_3dmodel.cpp
|
||||
* @brief
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include "3d_model.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "../3d_math.h"
|
||||
#include <utility>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/log.h>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
|
||||
/*
|
||||
* Flag to enable connectivity profiling.
|
||||
*
|
||||
* @ingroup trace_env_vars
|
||||
*/
|
||||
const wxChar* MODEL_3D::m_logTrace = wxT( "KI_TRACE_EDA_OGL_3DMODEL" );
|
||||
|
||||
|
||||
void MODEL_3D::MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
|
||||
GLuint* aIdxOut, const glm::vec4& aColor )
|
||||
{
|
||||
aVtxOut[0].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Min().z };
|
||||
aVtxOut[1].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Min().z };
|
||||
aVtxOut[2].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Min().z };
|
||||
aVtxOut[3].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Min().z };
|
||||
|
||||
aVtxOut[4].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Max().z };
|
||||
aVtxOut[5].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Max().z };
|
||||
aVtxOut[6].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Max().z };
|
||||
aVtxOut[7].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Max().z };
|
||||
|
||||
for( unsigned int i = 0; i < 8; ++i )
|
||||
aVtxOut[i].m_color = aVtxOut[i].m_cad_color = glm::clamp( aColor * 255.0f, 0.0f, 255.0f );
|
||||
|
||||
#define bbox_line( vtx_a, vtx_b )\
|
||||
do { *aIdxOut++ = vtx_a + aIdxOffset; \
|
||||
*aIdxOut++ = vtx_b + aIdxOffset; } while( 0 )
|
||||
|
||||
bbox_line( 0, 1 );
|
||||
bbox_line( 1, 2 );
|
||||
bbox_line( 2, 3 );
|
||||
bbox_line( 3, 0 );
|
||||
|
||||
bbox_line( 4, 5 );
|
||||
bbox_line( 5, 6 );
|
||||
bbox_line( 6, 7 );
|
||||
bbox_line( 7, 4 );
|
||||
|
||||
bbox_line( 0, 4 );
|
||||
bbox_line( 1, 5 );
|
||||
bbox_line( 2, 6 );
|
||||
bbox_line( 3, 7 );
|
||||
|
||||
#undef bbox_line
|
||||
}
|
||||
|
||||
|
||||
MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "MODEL_3D::MODEL_3D %u meshes %u materials" ),
|
||||
static_cast<unsigned int>( a3DModel.m_MeshesSize ),
|
||||
static_cast<unsigned int>( a3DModel.m_MaterialsSize ) );
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
GLuint buffers[8];
|
||||
|
||||
/**
|
||||
* WARNING: Horrible hack here!
|
||||
* Somehow, buffer values are being shared between pcbnew and the 3d viewer, which then frees
|
||||
* the buffer, resulting in errors in pcbnew. To resolve this temporarily, we generate
|
||||
* extra buffers in 3dviewer and use the higher numbers. These are freed on close.
|
||||
* todo: Correctly separate the OpenGL contexts to prevent overlapping buffer vals
|
||||
*/
|
||||
glGenBuffers( 6, buffers );
|
||||
m_bbox_vertex_buffer = buffers[2];
|
||||
m_bbox_index_buffer = buffers[3];
|
||||
m_vertex_buffer = buffers[4];
|
||||
m_index_buffer = buffers[5];
|
||||
|
||||
// Validate a3DModel pointers
|
||||
wxASSERT( a3DModel.m_Materials != nullptr );
|
||||
wxASSERT( a3DModel.m_Meshes != nullptr );
|
||||
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
||||
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
||||
|
||||
m_materialMode = aMaterialMode;
|
||||
|
||||
if( a3DModel.m_Materials == nullptr || a3DModel.m_Meshes == nullptr
|
||||
|| a3DModel.m_MaterialsSize == 0 || a3DModel.m_MeshesSize == 0 )
|
||||
return;
|
||||
|
||||
// create empty bbox for each mesh. it will be updated when the vertices are copied.
|
||||
m_meshes_bbox.resize( a3DModel.m_MeshesSize );
|
||||
|
||||
// copy materials for later use during rendering.
|
||||
m_materials.reserve( a3DModel.m_MaterialsSize );
|
||||
|
||||
for( unsigned int i = 0; i < a3DModel.m_MaterialsSize; ++i )
|
||||
m_materials.emplace_back( a3DModel.m_Materials[i] );
|
||||
|
||||
// build temporary vertex and index buffers for bounding boxes.
|
||||
// the first box is the outer box.
|
||||
std::vector<VERTEX> bbox_tmp_vertices( ( m_meshes_bbox.size() + 1 ) * bbox_vtx_count );
|
||||
std::vector<GLuint> bbox_tmp_indices( ( m_meshes_bbox.size() + 1 ) * bbox_idx_count );
|
||||
|
||||
// group all meshes by material.
|
||||
// for each material create a combined vertex and index buffer.
|
||||
// some models might have many sub-meshes. so iterate over the
|
||||
// input meshes only once.
|
||||
struct MESH_GROUP
|
||||
{
|
||||
std::vector<VERTEX> m_vertices;
|
||||
std::vector<GLuint> m_indices;
|
||||
};
|
||||
|
||||
std::vector<MESH_GROUP> mesh_groups( m_materials.size() );
|
||||
|
||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
||||
{
|
||||
const SMESH& mesh = a3DModel.m_Meshes[mesh_i];
|
||||
|
||||
// silently ignore meshes that have invalid material references or invalid geometry.
|
||||
if( mesh.m_MaterialIdx >= m_materials.size()
|
||||
|| mesh.m_Positions == nullptr
|
||||
|| mesh.m_FaceIdx == nullptr
|
||||
|| mesh.m_Normals == nullptr
|
||||
|| mesh.m_FaceIdxSize == 0
|
||||
|| mesh.m_VertexSize == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MESH_GROUP& mesh_group = mesh_groups[mesh.m_MaterialIdx];
|
||||
MATERIAL& material = m_materials[mesh.m_MaterialIdx];
|
||||
|
||||
if( material.IsTransparent() && m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
m_have_transparent_meshes = true;
|
||||
else
|
||||
m_have_opaque_meshes = true;
|
||||
|
||||
const unsigned int vtx_offset = mesh_group.m_vertices.size();
|
||||
mesh_group.m_vertices.resize( mesh_group.m_vertices.size() + mesh.m_VertexSize );
|
||||
|
||||
// copy vertex data and update the bounding box.
|
||||
// use material color for mesh bounding box or some sort of average vertex color.
|
||||
glm::vec3 avg_color = material.m_Diffuse;
|
||||
|
||||
BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i];
|
||||
|
||||
for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
|
||||
{
|
||||
mesh_bbox.Union( mesh.m_Positions[vtx_i] );
|
||||
|
||||
VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
|
||||
|
||||
vtx_out.m_pos = mesh.m_Positions[vtx_i];
|
||||
vtx_out.m_nrm = glm::clamp( glm::vec4( mesh.m_Normals[vtx_i], 1.0f ) * 127.0f,
|
||||
-127.0f, 127.0f );
|
||||
|
||||
vtx_out.m_tex_uv = mesh.m_Texcoords != nullptr ? mesh.m_Texcoords[vtx_i]
|
||||
: glm::vec2 (0);
|
||||
|
||||
if( mesh.m_Color != nullptr )
|
||||
{
|
||||
avg_color = ( avg_color + mesh.m_Color[vtx_i] ) * 0.5f;
|
||||
|
||||
vtx_out.m_color =
|
||||
glm::clamp( glm::vec4( mesh.m_Color[vtx_i],
|
||||
1 - material.m_Transparency ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
|
||||
vtx_out.m_cad_color =
|
||||
glm::clamp( glm::vec4( MaterialDiffuseToColorCAD( mesh.m_Color[vtx_i] ),
|
||||
1 ) * 255.0f, 0.0f, 255.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
// the mesh will be rendered with other meshes that might have
|
||||
// vertex colors. thus, we can't enable/disable vertex colors
|
||||
// for individual meshes during rendering.
|
||||
|
||||
// if there are no vertex colors, use material color instead.
|
||||
vtx_out.m_color =
|
||||
glm::clamp( glm::vec4( material.m_Diffuse,
|
||||
1 - material.m_Transparency ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
|
||||
vtx_out.m_cad_color =
|
||||
glm::clamp( glm::vec4 ( MaterialDiffuseToColorCAD( material.m_Diffuse ),
|
||||
1 ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
}
|
||||
}
|
||||
|
||||
if( mesh_bbox.IsInitialized() )
|
||||
{
|
||||
// generate geometry for the bounding box
|
||||
MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count,
|
||||
&bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count],
|
||||
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
|
||||
{ avg_color, 1.0f } );
|
||||
|
||||
// bump the outer bounding box
|
||||
m_model_bbox.Union( mesh_bbox );
|
||||
|
||||
// add to the material group
|
||||
material.m_bbox.Union( mesh_bbox );
|
||||
}
|
||||
|
||||
|
||||
// append indices of this mesh to the mesh group.
|
||||
const unsigned int idx_offset = mesh_group.m_indices.size();
|
||||
unsigned int use_idx_count = mesh.m_FaceIdxSize;
|
||||
|
||||
if( use_idx_count % 3 != 0 )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( " index count %u not multiple of 3, truncating" ),
|
||||
static_cast<unsigned int>( use_idx_count ) );
|
||||
use_idx_count = ( use_idx_count / 3 ) * 3;
|
||||
}
|
||||
|
||||
mesh_group.m_indices.resize( mesh_group.m_indices.size() + use_idx_count );
|
||||
|
||||
for( unsigned int idx_i = 0; idx_i < use_idx_count; ++idx_i )
|
||||
{
|
||||
if( mesh.m_FaceIdx[idx_i] >= mesh.m_VertexSize )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( " index %u out of range (%u)" ),
|
||||
static_cast<unsigned int>( mesh.m_FaceIdx[idx_i] ),
|
||||
static_cast<unsigned int>( mesh.m_VertexSize ) );
|
||||
|
||||
// FIXME: should skip this triangle
|
||||
}
|
||||
|
||||
mesh_group.m_indices[idx_offset + idx_i] = mesh.m_FaceIdx[idx_i] + vtx_offset;
|
||||
}
|
||||
}
|
||||
|
||||
// generate geometry for the outer bounding box
|
||||
if( m_model_bbox.IsInitialized() )
|
||||
MakeBbox( m_model_bbox, 0, &bbox_tmp_vertices[0], &bbox_tmp_indices[0],
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f } );
|
||||
|
||||
// create bounding box buffers
|
||||
glGenBuffers( 1, &m_bbox_vertex_buffer );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * bbox_tmp_vertices.size(),
|
||||
bbox_tmp_vertices.data(), GL_STATIC_DRAW );
|
||||
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||
|
||||
if( bbox_tmp_vertices.size() <= std::numeric_limits<GLushort>::max() )
|
||||
{
|
||||
m_bbox_index_buffer_type = GL_UNSIGNED_SHORT;
|
||||
|
||||
auto u16buf = std::make_unique<GLushort[]>( bbox_tmp_indices.size() );
|
||||
|
||||
for( unsigned int i = 0; i < bbox_tmp_indices.size(); ++i )
|
||||
u16buf[i] = static_cast<GLushort>( bbox_tmp_indices[i] );
|
||||
|
||||
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLushort ) * bbox_tmp_indices.size(),
|
||||
u16buf.get(), GL_STATIC_DRAW );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bbox_index_buffer_type = GL_UNSIGNED_INT;
|
||||
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLuint ) * bbox_tmp_indices.size(),
|
||||
bbox_tmp_indices.data(), GL_STATIC_DRAW );
|
||||
}
|
||||
|
||||
// merge the mesh group geometry data.
|
||||
unsigned int total_vertex_count = 0;
|
||||
unsigned int total_index_count = 0;
|
||||
|
||||
for( const MESH_GROUP& mg : mesh_groups )
|
||||
{
|
||||
total_vertex_count += mg.m_vertices.size();
|
||||
total_index_count += mg.m_indices.size();
|
||||
}
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( " total %u vertices, %u indices" ),
|
||||
total_vertex_count, total_index_count );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * total_vertex_count,
|
||||
nullptr, GL_STATIC_DRAW );
|
||||
|
||||
unsigned int idx_size = 0;
|
||||
|
||||
if( total_vertex_count <= std::numeric_limits<GLushort>::max() )
|
||||
{
|
||||
m_index_buffer_type = GL_UNSIGNED_SHORT;
|
||||
idx_size = sizeof( GLushort );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_index_buffer_type = GL_UNSIGNED_INT;
|
||||
idx_size = sizeof( GLuint );
|
||||
}
|
||||
|
||||
// temporary index buffer which will contain either GLushort or GLuint
|
||||
// type indices. allocate with a bit of meadow at the end.
|
||||
auto tmp_idx = std::make_unique<GLuint[]>( ( idx_size * total_index_count + 8 ) / sizeof( GLuint ) );
|
||||
|
||||
unsigned int prev_vtx_count = 0;
|
||||
unsigned int idx_offset = 0;
|
||||
unsigned int vtx_offset = 0;
|
||||
|
||||
for( unsigned int mg_i = 0; mg_i < mesh_groups.size (); ++mg_i )
|
||||
{
|
||||
MESH_GROUP& mg = mesh_groups[mg_i];
|
||||
MATERIAL& mat = m_materials[mg_i];
|
||||
uintptr_t tmp_idx_ptr = reinterpret_cast<uintptr_t>( tmp_idx.get() );
|
||||
|
||||
if( m_index_buffer_type == GL_UNSIGNED_SHORT )
|
||||
{
|
||||
GLushort* idx_out = reinterpret_cast<GLushort*>( tmp_idx_ptr + idx_offset );
|
||||
|
||||
for( GLuint idx : mg.m_indices )
|
||||
*idx_out++ = static_cast<GLushort>( idx + prev_vtx_count );
|
||||
}
|
||||
else if( m_index_buffer_type == GL_UNSIGNED_INT )
|
||||
{
|
||||
GLuint* idx_out = reinterpret_cast<GLuint*>( tmp_idx_ptr + idx_offset );
|
||||
|
||||
for( GLuint idx : mg.m_indices )
|
||||
*idx_out++ = static_cast<GLuint>( idx + prev_vtx_count );
|
||||
}
|
||||
|
||||
glBufferSubData( GL_ARRAY_BUFFER, vtx_offset, mg.m_vertices.size() * sizeof( VERTEX ),
|
||||
mg.m_vertices.data() );
|
||||
|
||||
mat.m_render_idx_buffer_offset = idx_offset;
|
||||
mat.m_render_idx_count = mg.m_indices.size();
|
||||
|
||||
prev_vtx_count += mg.m_vertices.size();
|
||||
idx_offset += mg.m_indices.size() * idx_size;
|
||||
vtx_offset += mg.m_vertices.size() * sizeof( VERTEX );
|
||||
}
|
||||
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
|
||||
glBufferData( GL_ELEMENT_ARRAY_BUFFER, idx_size * total_index_count, tmp_idx.get(),
|
||||
GL_STATIC_DRAW );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
wxLogTrace( m_logTrace, wxT( " loaded in %u ms\n" ),
|
||||
(unsigned int)std::chrono::duration_cast<std::chrono::milliseconds> (
|
||||
end_time - start_time).count() );
|
||||
}
|
||||
|
||||
|
||||
void MODEL_3D::BeginDrawMulti( bool aUseColorInformation )
|
||||
{
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glEnableClientState( GL_NORMAL_ARRAY );
|
||||
|
||||
if( aUseColorInformation )
|
||||
{
|
||||
glEnableClientState( GL_COLOR_ARRAY );
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
}
|
||||
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
}
|
||||
|
||||
|
||||
void MODEL_3D::EndDrawMulti()
|
||||
{
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
glDisableClientState( GL_NORMAL_ARRAY );
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||
}
|
||||
|
||||
|
||||
void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const
|
||||
{
|
||||
if( aOpacity <= FLT_EPSILON )
|
||||
return;
|
||||
|
||||
if( !glBindBuffer )
|
||||
throw std::runtime_error( "The OpenGL context no longer exists: unable to draw" );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
|
||||
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||
|
||||
glNormalPointer( GL_BYTE, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_nrm ) ) );
|
||||
|
||||
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( m_materialMode == MATERIAL_MODE::CAD_MODE
|
||||
? offsetof( VERTEX, m_cad_color )
|
||||
: offsetof( VERTEX, m_color ) ) );
|
||||
|
||||
glTexCoordPointer( 2, GL_FLOAT, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_tex_uv ) ) );
|
||||
|
||||
const SFVEC4F param = SFVEC4F( 1.0f, 1.0f, 1.0f, aOpacity );
|
||||
|
||||
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x );
|
||||
|
||||
std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
|
||||
|
||||
materialsToRender.reserve( m_materials.size() );
|
||||
|
||||
if( aModelWorldMatrix && aCameraWorldPos )
|
||||
{
|
||||
// Sort Material groups
|
||||
|
||||
std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
|
||||
|
||||
// Calculate the distance to the camera for each material group
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const BBOX_3D& bBox = mat.m_bbox;
|
||||
const SFVEC3F& bBoxCenter = bBox.GetCenter();
|
||||
const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
|
||||
|
||||
const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
|
||||
|
||||
materialsSorted.emplace_back( &mat, distanceToCamera );
|
||||
}
|
||||
|
||||
// Sort from back to front
|
||||
std::sort( materialsSorted.begin(), materialsSorted.end(),
|
||||
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
|
||||
std::pair<const MODEL_3D::MATERIAL*, float>& b )
|
||||
{
|
||||
bool aInsideB = a.first->m_bbox.Inside( b.first->m_bbox );
|
||||
bool bInsideA = b.first->m_bbox.Inside( a.first->m_bbox );
|
||||
|
||||
// If A is inside B, then A is rendered first
|
||||
if( aInsideB != bInsideA )
|
||||
return bInsideA;
|
||||
|
||||
if( a.second != b.second )
|
||||
return a.second > b.second;
|
||||
|
||||
return a.first > b.first; // compare pointers as a last resort
|
||||
} );
|
||||
|
||||
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
|
||||
{
|
||||
materialsToRender.push_back( mat.first );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
// There is at least one default material created in case a mesh has no declared materials.
|
||||
// Most meshes have a material, so usually the first material will have nothing to render and is skip.
|
||||
// See S3D::GetModel for more details.
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
materialsToRender.push_back( &mat );
|
||||
}
|
||||
}
|
||||
|
||||
for( const MODEL_3D::MATERIAL* mat : materialsToRender )
|
||||
{
|
||||
switch( m_materialMode )
|
||||
{
|
||||
case MATERIAL_MODE::NORMAL:
|
||||
OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||
OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::CAD_MODE:
|
||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
|
||||
aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type,
|
||||
reinterpret_cast<const void*>(
|
||||
static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MODEL_3D::~MODEL_3D()
|
||||
{
|
||||
if( glDeleteBuffers )
|
||||
{
|
||||
glDeleteBuffers( 1, &m_vertex_buffer );
|
||||
glDeleteBuffers( 1, &m_index_buffer );
|
||||
glDeleteBuffers( 1, &m_bbox_vertex_buffer );
|
||||
glDeleteBuffers( 1, &m_bbox_index_buffer );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MODEL_3D::DrawBbox() const
|
||||
{
|
||||
if( !glBindBuffer )
|
||||
throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bbox" );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||
|
||||
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
|
||||
|
||||
glDrawElements( GL_LINES, bbox_idx_count, m_bbox_index_buffer_type,
|
||||
reinterpret_cast<const void*>( 0 ) );
|
||||
}
|
||||
|
||||
|
||||
void MODEL_3D::DrawBboxes() const
|
||||
{
|
||||
if( !glBindBuffer )
|
||||
throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bboxes" );
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||
|
||||
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||
|
||||
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||
reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
|
||||
|
||||
unsigned int idx_size = m_bbox_index_buffer_type == GL_UNSIGNED_SHORT ? sizeof( GLushort )
|
||||
: sizeof( GLuint );
|
||||
|
||||
glDrawElements( GL_LINES, bbox_idx_count * m_meshes_bbox.size(), m_bbox_index_buffer_type,
|
||||
reinterpret_cast<const void*>(
|
||||
static_cast<uintptr_t>( bbox_idx_count * idx_size ) ) );
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef _MODEL_3D_H_
|
||||
#define _MODEL_3D_H_
|
||||
|
||||
#include <vector>
|
||||
#include <plugins/3dapi/c3dmodel.h>
|
||||
#include "../../common_ogl/openGL_includes.h"
|
||||
#include "../raytracing/shapes3D/bbox_3d.h"
|
||||
#include "../../3d_enums.h"
|
||||
|
||||
#include <wx/chartype.h>
|
||||
|
||||
class MODEL_3D
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Load a 3D model.
|
||||
*
|
||||
* @note This must be called inside a gl context.
|
||||
*
|
||||
* @param a3DModel a 3d model data to load.
|
||||
* @param aMaterialMode a mode to render the materials of the model.
|
||||
*/
|
||||
MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode );
|
||||
|
||||
~MODEL_3D();
|
||||
|
||||
/**
|
||||
* Render the model into the current context.
|
||||
*/
|
||||
void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model into the current context.
|
||||
*/
|
||||
void DrawTransparent( float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model into the current context.
|
||||
* if aModelWorldMatrix and aCameraWorldPos is provided,
|
||||
* it renders the material groups sorted.
|
||||
*/
|
||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const;
|
||||
|
||||
/**
|
||||
* Return true if have opaque meshes to render.
|
||||
*/
|
||||
bool HasOpaqueMeshes() const { return m_have_opaque_meshes; }
|
||||
|
||||
/**
|
||||
* Return true if have transparent mesh's to render.
|
||||
*/
|
||||
bool HasTransparentMeshes() const { return m_have_transparent_meshes; }
|
||||
|
||||
/**
|
||||
* Draw main bounding box of the model.
|
||||
*/
|
||||
void DrawBbox() const;
|
||||
|
||||
/**
|
||||
* Draw individual bounding boxes of each mesh.
|
||||
*/
|
||||
void DrawBboxes() const;
|
||||
|
||||
/**
|
||||
* Get the main bounding box.
|
||||
* @return the main model bounding box.
|
||||
*/
|
||||
const BBOX_3D& GetBBox() const { return m_model_bbox; }
|
||||
|
||||
/**
|
||||
* Set some basic render states before drawing multiple models.
|
||||
*/
|
||||
static void BeginDrawMulti( bool aUseColorInformation );
|
||||
|
||||
/**
|
||||
* Cleanup render states after drawing multiple models.
|
||||
*/
|
||||
static void EndDrawMulti();
|
||||
|
||||
private:
|
||||
static const wxChar* m_logTrace;
|
||||
|
||||
// the material mode that was used to generate the rendering data.
|
||||
// FIXME: this can be selected at run-time and does not require re-creation
|
||||
// of the whole model objects.
|
||||
MATERIAL_MODE m_materialMode;
|
||||
|
||||
BBOX_3D m_model_bbox; ///< global bounding box for this model
|
||||
std::vector<BBOX_3D> m_meshes_bbox; ///< individual bbox for each mesh
|
||||
|
||||
// unified vertex format for mesh rendering.
|
||||
struct VERTEX
|
||||
{
|
||||
glm::vec3 m_pos;
|
||||
glm::u8vec4 m_nrm; // only 3 components used
|
||||
glm::u8vec4 m_color; // regular color
|
||||
glm::u8vec4 m_cad_color; // "CAD" mode rendering color
|
||||
glm::vec2 m_tex_uv;
|
||||
};
|
||||
|
||||
// vertex buffer and index buffers that include all the individual meshes
|
||||
// lumped together.
|
||||
GLuint m_vertex_buffer = 0;
|
||||
GLuint m_index_buffer = 0;
|
||||
GLenum m_index_buffer_type = GL_INVALID_ENUM;
|
||||
|
||||
// internal material definition
|
||||
// all meshes are grouped by material for rendering purposes.
|
||||
struct MATERIAL : SMATERIAL
|
||||
{
|
||||
unsigned int m_render_idx_buffer_offset = 0;
|
||||
unsigned int m_render_idx_count = 0;
|
||||
|
||||
BBOX_3D m_bbox; ///< bounding box for this material group, used for transparent material ordering
|
||||
|
||||
MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { }
|
||||
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
|
||||
};
|
||||
|
||||
std::vector<MATERIAL> m_materials;
|
||||
|
||||
// a model can consist of transparent and opaque parts. remember which
|
||||
// ones are present during initial buffer and data setup. use it later
|
||||
// during rendering.
|
||||
bool m_have_opaque_meshes = false;
|
||||
bool m_have_transparent_meshes = false;
|
||||
|
||||
// vertex buffer and index buffer for the bounding boxes.
|
||||
// the first box is always the outer box, followed by inner boxes (one for each mesh).
|
||||
static constexpr unsigned int bbox_vtx_count = 8;
|
||||
static constexpr unsigned int bbox_idx_count = 24;
|
||||
|
||||
GLuint m_bbox_vertex_buffer = 0;
|
||||
GLuint m_bbox_index_buffer = 0;
|
||||
GLenum m_bbox_index_buffer_type = GL_INVALID_ENUM;
|
||||
|
||||
static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
|
||||
GLuint* aIdxOut, const glm::vec4& aColor );
|
||||
};
|
||||
|
||||
#endif // _MODEL_3D_H_
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user