diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93fd995 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/SigDN/nbproject/private/ +/SigDN/build/ +/JmeTests/nbproject/private/ +/JmeTests/build/ \ No newline at end of file diff --git a/Ar_SmallBow_mimiyala_D_00.obj b/Ar_SmallBow_mimiyala_D_00.obj new file mode 100644 index 0000000..0bcd03b --- /dev/null +++ b/Ar_SmallBow_mimiyala_D_00.obj @@ -0,0 +1,3231 @@ +# ???????? v1.0a + +v 0.033335 12.465958 26.857347 +v 0.078525 12.112000 -24.513327 +v 0.078525 12.112000 -24.513327 +v 0.033335 12.465958 26.857347 +v -0.711394 -0.518560 -9.647636 +v -1.063228 -1.537125 -10.188325 +v -0.906637 -1.281536 -10.711151 +v -1.144295 -2.444288 -10.670932 +v -0.925290 -1.635137 -10.242465 +v -0.588334 -3.204372 -8.624480 +v -1.330006 -3.387788 -10.714751 +v -1.550342 -4.319891 -11.183088 +v -1.329357 -5.152102 -9.694766 +v -1.656096 -4.899578 -10.874645 +v -1.756280 -5.454004 -11.150617 +v -1.987319 -6.913849 -10.595485 +v -1.860263 -5.046632 -9.659129 +v -1.656096 -4.899578 -10.874645 +v -1.715322 -2.982794 -8.548932 +v -1.330006 -3.387788 -10.714751 +v -1.063228 -1.537125 -10.188325 +v -2.096403 -8.020200 -9.137671 +v -1.046892 -6.288557 -7.264401 +v -0.568528 -4.082975 -6.408310 +v -0.255162 -1.753703 -7.296743 +v -0.169714 -2.172452 -5.565187 +v -0.271874 1.048114 -7.205420 +v -0.513801 0.248871 -5.642183 +v -1.329500 -1.946336 -5.487521 +v -1.333052 -1.543469 -7.224558 +v -1.767882 -3.847564 -6.327928 +v -2.220723 -6.055937 -7.185631 +v -0.609844 -0.352638 -8.692977 +v -0.670620 1.038064 -8.615867 +v -0.609844 -0.352638 -8.692977 +v -0.711394 -0.518560 -9.647636 +v -0.662125 -0.521159 -5.030962 +v -0.549129 -0.233476 -4.416174 +v -0.596906 -1.019838 -3.681961 +v -1.951577 -7.252577 -1.544504 +v -2.232930 -7.264988 -4.886656 +v -1.711625 -5.630106 -2.180991 +v -1.760725 -4.753367 -4.217858 +v -0.601902 -1.875403 -4.065059 +v -0.636888 -4.973744 -4.293175 +v -1.183219 -7.472794 -4.957087 +v -0.745372 -5.820366 -2.245677 +v -1.025999 -7.436610 -1.606424 +v -0.509845 -5.260381 -0.478669 +v -0.680696 -2.991035 -1.786441 +v -0.776487 -3.127855 -2.796412 +v -0.627384 -2.175530 -2.849646 +v -2.120722 -9.779284 -4.394672 +v -2.100377 -9.942679 -3.456064 +v -2.083340 -9.972002 -2.432547 +v -1.933356 -9.814237 -1.316197 +v -1.648643 -8.976278 -0.707092 +v -1.335032 -7.384756 0.672591 +v -1.103910 -6.165383 1.137769 +v -1.022317 -5.658915 0.811498 +v -0.963011 -5.057846 1.069653 +v -0.738585 -4.175320 0.593060 +v -0.660285 -3.354635 -0.434493 +v -1.489786 -5.064736 -0.413384 +v -0.738585 -4.175320 0.593060 +v -0.963011 -5.057846 1.069653 +v -1.022317 -5.658915 0.811498 +v -1.103910 -6.165383 1.137769 +v -1.335032 -7.384756 0.672591 +v -1.648643 -8.976278 -0.707092 +v -2.083340 -9.972002 -2.432547 +v -2.100377 -9.942679 -3.456064 +v -2.254679 -10.221931 -5.231500 +v -2.210604 -9.666483 -6.159724 +v -2.063477 -8.292387 -7.832534 +v -2.142375 -8.914450 -7.273056 +v -2.111325 -9.001485 -6.526379 +v 1.144294 -2.444289 -10.670932 +v 0.906636 -1.281536 -10.711151 +v 0.925289 -1.635137 -10.242465 +v 0.711394 -0.518560 -9.647636 +v 0.711394 -0.518560 -9.647636 +v 0.906636 -1.281536 -10.711151 +v 1.063228 -1.537125 -10.188325 +v 1.715322 -2.982794 -8.548932 +v 0.609844 -0.352638 -8.692977 +v 1.333052 -1.543469 -7.224558 +v 0.670621 1.038063 -8.615867 +v 0.271874 1.048114 -7.205420 +v 0.255162 -1.753703 -7.296743 +v 0.609844 -0.352638 -8.692977 +v 0.588334 -3.204372 -8.624480 +v 1.987319 -6.913849 -10.595485 +v 2.096403 -8.020200 -9.137671 +v 1.860263 -5.046632 -9.659129 +v 2.220723 -6.055937 -7.185631 +v 1.767882 -3.847564 -6.327928 +v 1.329500 -1.946336 -5.487521 +v 0.513801 0.248871 -5.642183 +v 0.169714 -2.172452 -5.565187 +v 0.568528 -4.082975 -6.408310 +v 1.046892 -6.288557 -7.264401 +v 1.329357 -5.152102 -9.694766 +v 1.025999 -7.436610 -1.606424 +v 1.183219 -7.472794 -4.957087 +v 0.745372 -5.820366 -2.245677 +v 0.636888 -4.973744 -4.293175 +v 0.601902 -1.875403 -4.065059 +v 0.596906 -1.019838 -3.681961 +v 1.760725 -4.753367 -4.217858 +v 2.232930 -7.264988 -4.886656 +v 1.711625 -5.630106 -2.180991 +v 1.951577 -7.252577 -1.544504 +v 1.489786 -5.064736 -0.413384 +v 0.680696 -2.991035 -1.786441 +v 0.776487 -3.127855 -2.796412 +v 0.627384 -2.175530 -2.849646 +v 0.509845 -5.260381 -0.478669 +v 0.660285 -3.354635 -0.434493 +v 0.738585 -4.175320 0.593060 +v 0.963011 -5.057846 1.069653 +v 1.022317 -5.658915 0.811498 +v 1.103910 -6.165383 1.137769 +v 1.335032 -7.384756 0.672591 +v 1.648643 -8.976278 -0.707092 +v 1.933356 -9.814237 -1.316197 +v 2.083340 -9.972002 -2.432547 +v 2.100377 -9.942679 -3.456064 +v 2.120722 -9.779284 -4.394672 +v 0.738585 -4.175320 0.593060 +v 0.963011 -5.057846 1.069653 +v 1.022317 -5.658915 0.811498 +v 1.103910 -6.165383 1.137769 +v 1.335032 -7.384756 0.672591 +v 1.648643 -8.976278 -0.707092 +v 2.083340 -9.972002 -2.432547 +v 2.100377 -9.942679 -3.456064 +v 2.254679 -10.221931 -5.231500 +v 2.210604 -9.666483 -6.159724 +v 2.063477 -8.292387 -7.832534 +v 2.142375 -8.914450 -7.273056 +v 2.111325 -9.001485 -6.526379 +v -0.925290 -1.635137 -10.242465 +v -0.906637 -1.281536 -10.711151 +v 0.791150 13.771201 26.945435 +v -0.000875 14.259495 26.711082 +v -0.000747 13.447573 26.213821 +v -0.792664 13.770877 26.945557 +v 0.786292 13.702822 28.171816 +v -0.000661 13.410592 27.248886 +v 0.771569 12.772246 26.555729 +v -0.000606 12.732074 26.147089 +v -0.772735 12.771931 26.555847 +v -0.787592 13.702500 28.171934 +v -0.000605 13.336007 27.780415 +v -0.733811 11.262825 27.469223 +v -0.000323 11.732838 27.182083 +v -0.687412 10.329016 25.879278 +v -0.000114 9.762869 24.640812 +v -0.653980 7.764967 24.186707 +v 0.000113 8.179344 23.376873 +v -0.618752 4.692291 21.060135 +v 0.733402 11.263124 27.469110 +v 0.687141 10.329297 25.879173 +v 0.654529 7.655302 24.289642 +v 0.619724 4.692481 21.060064 +v 0.000584 6.329863 24.590744 +v 0.000360 7.952672 26.001913 +v -0.000300 12.160233 28.626518 +v 0.000026 10.311899 27.947802 +v 0.000025 9.728546 26.369215 +v -0.660483 9.129943 26.171070 +v 0.000137 9.376820 26.893814 +v 0.660747 9.130213 26.170969 +v -0.000608 13.686560 28.673191 +v 0.000044 9.776823 26.746273 +v 0.000035 10.002254 27.228336 +v -0.000875 14.259495 26.711082 +v -0.000848 14.588611 27.945621 +v -0.490255 -1.477050 -2.018391 +v -0.000001 -0.778592 -1.224683 +v -0.456943 -2.245757 -0.021810 +v -0.000001 -1.390482 -0.025869 +v 0.456941 -2.245757 -0.021810 +v 0.490254 -1.477050 -2.018391 +v -0.000001 -3.149030 -0.010307 +v 0.443418 -2.202862 -2.423325 +v 0.731017 0.550368 -2.880855 +v -0.000001 0.559338 -3.991405 +v 0.779199 3.014162 -2.173558 +v -0.000001 3.545451 -2.669302 +v -0.000001 4.110758 0.013362 +v -0.779200 3.014162 -2.173558 +v -0.731019 0.550368 -2.880855 +v -0.443419 -2.202862 -2.423325 +v -0.000001 0.543590 -1.864378 +v -0.000001 2.088090 -1.531556 +v 0.854307 3.400594 0.021478 +v -0.000001 3.626095 2.657550 +v 0.833910 2.965693 2.025817 +v 0.608564 0.745311 4.066879 +v 0.549344 0.753867 3.165375 +v 0.556381 -0.205171 3.990686 +v 0.475334 -1.280996 2.496390 +v -0.854308 3.400589 0.021288 +v -0.833912 2.965433 2.016166 +v -0.608565 0.744959 4.053804 +v -0.549346 0.753619 3.156186 +v -0.556382 -0.205458 3.980045 +v -0.475335 -1.281109 2.492208 +v -0.000001 -2.122077 3.211963 +v -0.000001 -0.554102 4.068545 +v -0.000001 -0.647164 1.721476 +v -0.000001 0.763844 2.070565 +v -0.000001 2.121930 1.420189 +v -0.000001 2.233989 0.037198 +v 0.033335 12.465958 26.857347 +v 0.026520 12.639213 26.851110 +v -0.000030 12.088541 -0.040912 +v -0.000080 12.324107 -0.047163 +v 0.071753 12.285265 -24.519423 +v 0.078525 12.112000 -24.513327 +v 0.727631 5.298484 -10.021182 +v 0.715328 4.926592 -7.997160 +v 0.000004 5.767903 -9.625628 +v 0.000001 5.545123 -8.004004 +v -0.715326 4.926592 -7.997160 +v -0.727623 5.298485 -10.021182 +v 0.000004 5.723817 -10.547132 +v -0.720007 4.686525 -11.329148 +v 0.000004 5.027155 -11.627799 +v 0.000003 4.086179 -11.796777 +v -0.698911 3.827301 -10.726620 +v 0.000002 3.390660 -11.249069 +v 0.000002 3.359813 -10.328207 +v 0.698916 3.827300 -10.726620 +v 0.720014 4.686524 -11.329148 +v 0.000004 4.905285 -9.913692 +v 0.000003 4.619989 -10.837653 +v 0.000003 4.148826 -10.571314 +v 0.000003 4.167034 -9.827177 +v 0.000001 4.473603 -8.095013 +v -0.694568 4.170340 -6.497423 +v 0.694566 4.170340 -6.497423 +v -0.000001 4.946384 -6.349893 +v -0.000001 -3.149030 -0.010307 +v 0.443418 -2.202862 -2.423325 +v 0.473819 -5.202638 1.016256 +v 0.530100 -3.115210 -3.587555 +v 0.635679 1.059093 -4.999258 +v -0.000001 1.327689 -6.133102 +v 0.664294 2.745227 -5.563175 +v -0.000001 2.237640 -6.665078 +v -0.000001 3.681902 -7.004555 +v -0.664296 2.745227 -5.563175 +v -0.635680 1.059093 -4.999258 +v -0.530102 -3.115210 -3.587555 +v -0.582547 -1.286044 -8.086959 +v 0.473449 -5.084811 3.101434 +v -0.000001 -3.955505 3.470398 +v -0.000001 -4.450434 7.403558 +v -0.473450 -5.084811 3.101434 +v -0.473821 -5.202638 1.016256 +v -0.443419 -2.202862 -2.423325 +v -0.000001 0.559338 -3.991405 +v -0.000001 3.175179 -4.579239 +v -0.000001 4.553290 -5.767457 +v -0.709082 4.885360 -5.992791 +v 0.709081 4.885360 -5.992791 +v -0.000001 5.273266 -6.022921 +v -0.000001 5.101686 -5.374474 +v -0.000001 4.848416 -5.712872 +v 0.000027 6.292016 -15.518654 +v 0.770296 5.759637 -16.018311 +v 0.000023 5.326952 -15.749665 +v 0.737174 4.244362 -15.923318 +v 0.000023 5.451621 -16.335602 +v -0.770247 5.759644 -16.018311 +v 0.000019 4.501259 -16.409763 +v -0.737137 4.244369 -15.923318 +v -0.674639 1.480417 -14.759708 +v 0.000015 3.449885 -15.143359 +v 0.000019 4.433312 -15.590542 +v -0.787453 6.625865 -15.640450 +v 0.000027 6.165401 -15.227983 +v 0.000028 6.578146 -14.998548 +v 0.787510 6.625857 -15.640450 +v 0.000027 6.209963 -16.198696 +v 0.674650 1.480411 -14.759708 +v 0.000009 2.176589 -14.194275 +v 0.000011 2.601560 -13.636290 +v 0.629783 0.472582 -12.581440 +v -0.000000 0.123519 -15.476410 +v 0.000005 1.276634 -16.314709 +v -0.629782 0.472585 -12.581440 +v 0.000030 6.856548 -15.895739 +v 0.000030 6.991513 -15.371705 +v -0.000001 -2.277236 -11.030389 +v 0.582545 -1.286044 -8.086959 +v -0.000005 -1.680977 -13.222477 +v -0.000002 -0.354420 -15.001658 +v 0.000005 1.969830 -11.496403 +v -0.000000 1.153971 -9.622580 +v -0.681693 1.132750 -8.751707 +v -0.000000 1.922248 -8.060241 +v 0.000000 2.467011 -8.855666 +v 0.681693 1.132750 -8.751707 +v -0.000001 -3.317901 -7.372544 +v -0.000000 1.846606 -9.961455 +v 0.000000 2.850566 -9.932386 +v 0.475325 -5.640247 7.290706 +v -0.000001 -6.065223 4.547241 +v 0.441405 -6.547158 2.946075 +v -0.000001 -6.468287 1.053617 +v -0.000001 -5.756346 -2.267148 +v -0.000001 -4.355916 -4.926816 +v -0.441406 -6.547158 2.946075 +v -0.475326 -5.640331 7.287594 +v 0.480030 -5.054593 9.973497 +v 0.000248 -5.939615 10.163409 +v 0.464040 -5.481124 10.435408 +v 0.000667 -5.750462 12.574707 +v 0.464184 -5.038054 13.049288 +v 0.000641 -4.847165 13.942278 +v 0.000540 -3.103746 14.374965 +v -0.462919 -5.038243 13.044529 +v -0.463562 -5.481274 10.430776 +v -0.479590 -4.813452 9.830377 +v 0.000227 -5.046788 10.332033 +v 0.000195 -3.426308 11.392807 +v 0.000596 -4.620480 12.647087 +v 0.000198 -4.282234 9.388001 +v -0.491837 -2.878618 13.802740 +v 0.000502 -2.794700 13.605698 +v 0.492862 -2.878295 13.812318 +v 0.000503 -2.513802 14.379827 +v -0.504501 -2.410965 13.642605 +v 0.000453 -2.591187 12.099585 +v 0.505459 -2.410597 13.653811 +v 0.000461 -2.011319 13.968966 +v 0.000451 -2.062547 13.405457 +v 1.231569 10.107820 -21.695753 +v 0.984468 8.958984 -20.996614 +v 0.757261 8.789785 -21.805237 +v 0.766336 8.584978 -20.475336 +v 1.411597 12.114138 -21.433668 +v 1.248545 11.008051 -20.114750 +v 1.006005 9.675652 -19.986622 +v 0.870255 9.127699 -20.454424 +v 1.077003 8.958745 -21.002430 +v 1.006005 9.675652 -19.986622 +v 1.324106 10.107581 -21.701571 +v 1.248545 11.008051 -20.114750 +v 1.411597 12.114138 -21.433668 +v 1.455849 12.375481 -22.042145 +v 1.429242 10.852894 -23.322586 +v 1.389198 12.170208 -22.792023 +v 1.404326 12.446342 -23.593157 +v 1.436735 11.236096 -24.875343 +v 1.348856 12.347502 -24.552212 +v 0.818713 9.361172 -23.114683 +v 0.911292 9.989637 -23.859825 +v 0.928094 10.248794 -24.758486 +v 1.001773 10.806403 -25.655249 +v 1.102114 11.374768 -25.869278 +v 1.344198 11.236334 -24.869530 +v 1.336707 10.853130 -23.316769 +v 1.213439 11.887144 -25.483307 +v 1.348856 12.347502 -24.552212 +v 1.404326 12.446342 -23.593157 +v 1.389198 12.170208 -22.792023 +v 1.455849 12.375481 -22.042145 +v -1.323996 10.107594 -21.701571 +v -1.076905 8.958755 -21.002430 +v -0.757164 8.789793 -21.805237 +v -0.766241 8.584986 -20.475336 +v -1.248427 11.008063 -20.114750 +v -1.231459 10.107832 -21.695753 +v -1.005900 9.675663 -19.986622 +v -0.984369 8.958994 -20.996614 +v -0.870155 9.127708 -20.454424 +v -1.005900 9.675663 -19.986622 +v -1.248427 11.008063 -20.114750 +v -1.411466 12.114151 -21.433668 +v -1.455716 12.375495 -22.042145 +v -1.429124 10.852908 -23.322586 +v -1.389067 12.170223 -22.792023 +v -1.404192 12.446356 -23.593157 +v -1.436612 11.236112 -24.875343 +v -1.348723 12.347515 -24.552212 +v -1.213310 11.887156 -25.483307 +v -0.818610 9.361179 -23.114683 +v -1.336589 10.853144 -23.316769 +v -0.911183 9.989647 -23.859825 +v -0.927982 10.248802 -24.758486 +v -1.344076 11.236347 -24.869530 +v -1.001654 10.806414 -25.655249 +v -1.101990 11.374779 -25.869278 +v -1.348723 12.347515 -24.552212 +v -1.404192 12.446356 -23.593157 +v -1.389067 12.170223 -22.792023 +v -1.455716 12.375495 -22.042145 +v -1.411466 12.114151 -21.433668 +v 0.078525 12.112000 -24.513327 +v 0.071753 12.285265 -24.519423 +v -0.000030 12.088541 -0.040912 +v -0.000080 12.324107 -0.047163 +v 0.026520 12.639213 26.851110 +v 0.033335 12.465958 26.857347 +v -0.772735 12.771931 26.555847 +v -0.000489 12.298326 26.513813 +v -0.000438 12.304338 27.201513 +v 0.771569 12.772246 26.555729 +v -0.000545 12.900728 27.390926 +v 1.381425 0.695494 4.181331 +v 1.387732 -0.313080 4.667441 +v 1.558785 1.701453 4.566619 +v 1.574015 -0.724890 5.739588 +v 1.815919 2.131153 5.601709 +v 1.831153 -0.296406 6.773235 +v 2.002206 1.732792 6.680150 +v 2.008511 0.724786 7.164889 +v -2.008512 0.722962 7.097201 +v -1.831154 -0.297869 6.719021 +v -2.002206 1.730975 6.612685 +v -1.815919 2.129715 5.548173 +v -1.574015 -0.725934 5.700820 +v -1.558785 1.700430 4.528610 +v -1.387731 -0.313880 4.637734 +v -1.381425 0.694703 4.151936 +v 1.717532 -2.783506 -5.499582 +v 1.972820 -3.792544 -5.160076 +v 1.371360 -1.948731 -4.985989 +v 1.987677 -4.324654 -4.163685 +v 1.137089 -1.763963 -3.919550 +v 1.753412 -4.067318 -3.094041 +v 1.151955 -2.264332 -2.921755 +v 1.407239 -3.183261 -2.578267 +v -1.407237 -3.183080 -2.578261 +v -1.753409 -4.067319 -3.094047 +v -1.151952 -2.454448 -2.685249 +v -1.137087 -1.762414 -3.919481 +v -1.987674 -4.324653 -4.163684 +v -1.371358 -1.947533 -4.985931 +v -1.972817 -3.792544 -5.160076 +v -1.717529 -2.783507 -5.499582 +v 0.000054 11.017597 -26.327961 +v -0.976887 9.928164 -26.905657 +v 0.000053 10.846407 -27.137589 +v 0.000049 9.912538 -28.225302 +v 0.976985 9.928152 -26.905657 +v 0.000045 9.227898 -26.732979 +v -0.981134 10.047430 -24.629562 +v -1.009024 11.685095 -25.737518 +v 0.000057 11.583292 -26.957027 +v 0.000063 12.783377 -27.162548 +v 1.009140 11.685085 -25.737518 +v 0.981233 10.047421 -24.629562 +v 0.000041 8.448265 -27.391510 +v -0.720263 8.674064 -27.755785 +v 0.000042 8.484313 -28.297005 +v 0.720349 8.674057 -27.755785 +v 0.000037 7.498720 -27.384291 +v 0.000049 10.037499 -23.110989 +v -0.926713 8.535069 -21.925892 +v 0.000053 10.835856 -24.160711 +v -1.020015 11.844249 -24.743217 +v 0.000061 12.357675 -25.409231 +v 0.000063 12.721844 -25.353479 +v 1.020132 11.844238 -24.743217 +v 0.926796 8.535060 -21.925892 +v 0.000062 12.602228 -25.894241 +v 0.000061 12.432257 -24.526529 +v 0.000063 12.783872 -24.753363 +v 0.000064 13.055110 -25.094402 +v 0.000029 6.667139 -18.024633 +v -0.764722 4.979301 -18.519493 +v 0.000039 7.905863 -19.596979 +v 0.000043 8.840112 -20.642033 +v 0.764764 4.979294 -18.519493 +v 0.000010 2.342613 -17.771107 +v 0.000015 3.588214 -19.856228 +v 0.787366 4.875538 -20.785349 +v 0.000018 4.298360 -21.034756 +v 0.000026 6.069904 -22.483164 +v -0.787324 4.875545 -20.785349 +v 0.000024 5.627002 -20.944712 +v 0.000039 7.985207 -22.708042 +v 0.000046 9.355299 -25.041351 +v -0.000001 -6.444484 7.272361 +v -0.000001 -8.301946 4.105545 +v -0.000001 -8.727839 7.626991 +v -0.000001 -7.330117 2.171356 +v 0.000372 4.005163 17.235386 +v -0.611519 2.730855 15.617998 +v 0.000086 6.041237 17.692141 +v 0.000202 4.881505 16.600868 +v 0.612557 2.272184 15.921064 +v -0.000001 3.626095 2.657550 +v 0.608564 0.745311 4.066879 +v 0.638732 3.775324 9.381661 +v 0.603644 1.662331 10.907145 +v -0.000023 4.422508 10.897139 +v 0.000124 4.648514 14.614741 +v -0.603376 2.162052 10.641265 +v -0.638747 3.774525 9.353251 +v -0.608565 0.744959 4.053804 +v -0.000044 5.104931 9.137649 +v -0.000046 5.469971 9.936747 +v -0.000077 5.342268 11.121464 +v -0.000001 -0.554102 4.068545 +v 0.550949 -1.598009 7.194028 +v 0.556381 -0.205171 3.990686 +v 0.000374 -1.538117 11.599786 +v 0.000974 -0.791316 14.900673 +v 0.000932 0.204332 16.839563 +v -0.563895 0.625792 17.227806 +v 0.001023 -0.229872 17.254980 +v -0.396167 -0.223506 17.542999 +v 0.001055 -0.524656 17.029509 +v 0.001190 -1.540114 16.663841 +v 0.398243 -0.223292 17.546377 +v 0.565675 0.626147 17.234447 +v 0.001015 0.078151 17.944000 +v 0.000889 0.911125 17.980484 +v -0.603730 2.684344 16.951832 +v 0.000285 5.725305 20.311619 +v 0.604865 2.780153 17.502102 +v 0.000799 2.513881 20.694769 +v 0.000656 4.165842 22.624851 +v 2.056452 4.718231 7.667467 +v 1.189990 3.415120 7.008384 +v 2.172298 5.993126 7.423817 +v 2.113879 6.886080 6.775423 +v 2.085973 3.372467 6.763079 +v 1.863891 6.101632 6.314280 +v 1.597039 4.854266 6.018266 +v 2.165926 1.516863 9.522537 +v 2.445366 2.647767 9.963815 +v 2.151595 1.263360 8.160884 +v 2.379056 3.258697 9.225636 +v 2.335026 3.850722 9.016232 +v 2.215217 3.693832 7.801348 +v 1.590883 0.873853 6.281160 +v 1.374646 3.465233 4.651816 +v 1.488255 6.045631 5.039018 +v 0.706217 3.510609 4.831244 +v 0.736306 0.919536 6.497772 +v 1.352195 1.243507 8.366116 +v 1.567649 -1.925568 9.061533 +v 2.070001 -0.863589 10.141194 +v 2.255129 0.415980 10.247892 +v 2.070001 -0.863589 10.141194 +v 1.567649 -1.925568 9.061533 +v 1.101329 -2.374137 7.561985 +v 0.890031 -2.618015 6.836680 +v 0.849911 1.514413 5.005697 +v 0.685059 0.544102 4.861802 +v 0.720919 -0.411443 5.409041 +v 0.668499 2.170742 4.056866 +v 0.401552 4.832547 3.038573 +v 0.604952 -1.554626 5.493797 +v 0.626261 -2.693357 6.049875 +v 0.951121 4.792202 2.885606 +v 0.535675 4.136153 2.798371 +v 0.586704 5.470407 2.486575 +v 0.815190 5.400922 3.125624 +v 1.028609 5.160836 3.868653 +v 1.223635 5.733932 4.267957 +v 0.815190 5.400922 3.125624 +v -1.597038 4.853010 5.971638 +v -1.189990 3.413936 6.964373 +v -1.863892 6.100323 6.265694 +v -2.113879 6.884714 6.724541 +v -2.085973 3.370554 6.692065 +v -2.172298 5.991398 7.359791 +v -2.056451 4.716298 7.595712 +v -2.165926 1.514462 9.433393 +v -2.445366 2.645020 9.861841 +v -1.352196 1.242030 8.311323 +v -2.379055 3.256069 9.128201 +v -2.335026 3.848226 8.923470 +v -1.714223 3.674119 7.868301 +v -0.736307 0.918869 6.472997 +v -0.706217 3.510098 4.812301 +v -1.488255 6.044763 5.006759 +v -1.374645 3.464303 4.617176 +v -1.590884 0.872508 6.231241 +v -2.151594 1.261160 8.079291 +v -1.567650 -1.926759 9.017303 +v -2.070002 -0.865415 10.073349 +v -2.255130 0.413699 10.163120 +v -2.070002 -0.865415 10.073349 +v -1.567650 -1.926759 9.017303 +v -1.101329 -2.374854 7.535387 +v -0.890032 -2.618527 6.817689 +v -0.849911 1.513788 4.982471 +v -0.685060 0.543639 4.844598 +v -0.720920 -0.411931 5.390877 +v -0.668500 2.170329 4.041522 +v -0.951121 4.791833 2.871769 +v -0.604952 -1.554978 5.480697 +v -0.626261 -2.693676 6.038097 +v -0.401552 4.832375 3.032300 +v -0.535674 4.135931 2.790194 +v -0.586703 5.470227 2.479914 +v -0.815190 5.400599 3.113599 +v -1.028609 5.160310 3.849172 +v -1.223634 5.733295 4.244290 +v -0.815190 5.400599 3.113599 +v 2.445366 2.647767 9.963815 +v 2.379056 3.258697 9.225636 +v 1.714222 3.675927 7.935408 +v 0.662125 -0.521159 -5.030962 +v 0.549129 -0.233476 -4.416174 +v -2.445366 2.645020 9.861841 +v -2.379055 3.256069 9.128201 +v -2.215216 3.691607 7.718815 +v 0.001092 -0.436130 17.909294 +v 0.001123 -0.752220 17.598110 +v -0.000001 -2.122077 3.211963 +v -0.475335 -1.281109 2.492208 +v -0.000001 -0.647164 1.721476 +v 0.475334 -1.280996 2.496390 +v -0.550951 -1.598415 7.178939 +v -0.000001 -2.003046 7.342428 +v -0.556382 -0.205458 3.980045 +v -1.574015 -0.725934 5.700820 +v -1.831154 -0.297869 6.719021 +v -0.803651 -0.662620 5.875037 +v -1.060783 -0.241078 6.896059 +v -2.008512 0.722962 7.097201 +v -1.238144 0.778906 7.276483 +v -2.002206 1.730975 6.612685 +v -1.231835 1.793350 6.791883 +v -1.815919 2.129715 5.548173 +v -1.045559 2.198534 5.724907 +v -1.558785 1.700430 4.528610 +v -0.788421 1.773197 4.702336 +v -1.381425 0.694703 4.151936 +v -0.611062 0.766570 4.323876 +v -1.387731 -0.313880 4.637734 +v -0.617366 -0.243541 4.809967 +v -1.574015 -0.725934 5.700820 +v -0.803651 -0.662620 5.875037 +v -1.987674 -4.324653 -4.163684 +v -1.753409 -4.067319 -3.094047 +v -1.241198 -4.559686 -4.283411 +v -1.006925 -4.301770 -3.213748 +v -1.407237 -3.183080 -2.578261 +v -0.660756 -3.412001 -2.697721 +v -1.151952 -2.454448 -2.685249 +v -0.723749 -2.389220 -2.726819 +v -1.137087 -1.762414 -3.919481 +v -0.708893 -1.857974 -4.039440 +v -1.371358 -1.947533 -4.985931 +v -0.624878 -2.176641 -5.105399 +v -1.717529 -2.783507 -5.499582 +v -0.971054 -3.017686 -5.619273 +v -1.972817 -3.792544 -5.160076 +v -1.226334 -4.027485 -5.279800 +v -1.987674 -4.324653 -4.163684 +v -1.241198 -4.559686 -4.283411 +v 0.803651 -0.662049 5.896260 +v 1.574015 -0.724890 5.739588 +v 0.617366 -0.243158 4.824203 +v 1.387732 -0.313080 4.667441 +v 0.611062 0.766950 4.337892 +v 1.381425 0.695494 4.181331 +v 0.788421 1.773754 4.722977 +v 1.558785 1.701453 4.566619 +v 1.045559 2.199425 5.757897 +v 1.815919 2.131153 5.601709 +v 1.231835 1.794546 6.836306 +v 2.002206 1.732792 6.680150 +v 1.238144 0.780107 7.321103 +v 2.008511 0.724786 7.164889 +v 1.060782 -0.240172 6.929615 +v 1.831153 -0.296406 6.773235 +v 0.803651 -0.662049 5.896260 +v 1.574015 -0.724890 5.739588 +v 1.241201 -4.559686 -4.283409 +v 1.987677 -4.324654 -4.163685 +v 1.226337 -4.027485 -5.279800 +v 1.972820 -3.792544 -5.160076 +v 0.971057 -3.017684 -5.619273 +v 1.717532 -2.783506 -5.499582 +v 0.624881 -2.177163 -5.105424 +v 1.371360 -1.948731 -4.985989 +v 0.708896 -1.858958 -4.039484 +v 1.137089 -1.763963 -3.919550 +v 0.723751 -2.346445 -3.041123 +v 1.151955 -2.264332 -2.921755 +v 0.660758 -3.412000 -2.697720 +v 1.407239 -3.183261 -2.578267 +v 1.006928 -4.301772 -3.213754 +v 1.753412 -4.067318 -3.094041 +v 1.241201 -4.559686 -4.283409 +v 1.987677 -4.324654 -4.163685 +v 0.925289 -1.635137 -10.242465 +v 1.330004 -3.387789 -10.714751 +v 1.550339 -4.319892 -11.183088 +v 1.656093 -4.899579 -10.874645 +v 1.756277 -5.454005 -11.150617 +v 1.656093 -4.899579 -10.874645 +v 1.330004 -3.387789 -10.714751 +v 1.063228 -1.537125 -10.188325 + +vn -0.999228 -0.039236 0.001790 +vn -0.999227 -0.039168 -0.003245 +vn 0.999227 0.039168 0.003245 +vn 0.999228 0.039236 -0.001790 +vn 0.151112 0.884059 -0.442272 +vn -0.948949 0.285527 -0.134052 +vn 0.113474 0.435534 -0.892992 +vn -0.021892 0.105066 -0.994224 +vn 0.974755 -0.126233 -0.184166 +vn 0.971268 -0.135332 -0.195765 +vn 0.013723 0.310134 -0.950594 +vn -0.071188 -0.030536 -0.996995 +vn 0.941935 -0.238070 -0.236815 +vn -0.134331 -0.069796 -0.988476 +vn -0.060286 0.003901 -0.998173 +vn -0.164785 -0.629952 -0.758950 +vn -0.987315 0.117178 -0.107135 +vn -0.134331 -0.069796 -0.988476 +vn -0.969961 0.232529 -0.071450 +vn 0.013723 0.310134 -0.950594 +vn -0.948949 0.285527 -0.134052 +vn -0.186022 -0.822528 -0.537441 +vn 0.949829 -0.278586 -0.142180 +vn 0.986712 -0.160483 -0.025373 +vn 0.989730 -0.047725 -0.134750 +vn 0.982575 -0.118182 0.143455 +vn 0.261965 0.957399 0.121494 +vn 0.033524 0.819839 0.571612 +vn -0.953688 0.174311 0.245144 +vn -0.953664 0.300865 -0.002492 +vn -0.972378 0.207707 0.106487 +vn -0.996495 0.082030 -0.016392 +vn 0.236669 0.447972 -0.862154 +vn -0.054849 0.774390 -0.630326 +vn 0.236669 0.447972 -0.862154 +vn 0.151112 0.884059 -0.442272 +vn -0.083537 0.982162 0.168464 +vn 0.111470 0.957371 0.266486 +vn 0.046109 0.237667 0.970252 +vn -0.983955 0.066133 0.165706 +vn -0.996890 0.062398 0.048141 +vn -0.964846 0.250206 0.080431 +vn -0.955564 0.263257 0.132636 +vn 0.206044 -0.060019 0.976700 +vn 0.994509 -0.104383 0.007543 +vn 0.950876 -0.300224 -0.075502 +vn 0.991824 -0.117375 -0.050085 +vn 0.957691 -0.287109 0.019907 +vn 0.991539 -0.098831 0.084161 +vn 0.183580 0.981916 -0.046262 +vn 0.174943 0.468114 0.866178 +vn 0.154039 0.694748 0.702565 +vn -0.167072 -0.973864 0.153868 +vn -0.184202 -0.982635 -0.022343 +vn -0.223548 -0.973428 0.049633 +vn -0.125745 -0.880038 0.457953 +vn 0.038513 -0.621704 0.782305 +vn -0.035461 -0.506860 0.861299 +vn 0.037901 -0.035945 0.998635 +vn 0.137128 0.267776 0.953673 +vn -0.007888 0.046794 0.998873 +vn 0.192284 0.616136 0.763809 +vn 0.194063 0.894732 0.402237 +vn -0.943815 0.265487 0.196800 +vn 0.192284 0.616136 0.763809 +vn -0.007888 0.046794 0.998873 +vn 0.137128 0.267776 0.953673 +vn 0.037901 -0.035945 0.998635 +vn -0.035461 -0.506860 0.861299 +vn 0.038513 -0.621704 0.782305 +vn -0.223548 -0.973428 0.049633 +vn -0.184202 -0.982635 -0.022343 +vn -0.184004 -0.982235 -0.036844 +vn -0.173821 -0.703839 -0.688765 +vn -0.186411 -0.813115 -0.551448 +vn -0.190373 -0.877950 -0.439274 +vn -0.190122 -0.857053 -0.478868 +vn 0.021891 0.105066 -0.994224 +vn -0.113474 0.435534 -0.892992 +vn -0.974756 -0.126233 -0.184165 +vn -0.151111 0.884059 -0.442272 +vn -0.151111 0.884059 -0.442272 +vn -0.113474 0.435534 -0.892992 +vn 0.948949 0.285527 -0.134052 +vn 0.969961 0.232529 -0.071450 +vn -0.236669 0.447972 -0.862153 +vn 0.953664 0.300865 -0.002492 +vn 0.054849 0.774390 -0.630326 +vn -0.261965 0.957399 0.121494 +vn -0.989730 -0.047725 -0.134750 +vn -0.236669 0.447972 -0.862153 +vn -0.971268 -0.135332 -0.195765 +vn 0.164785 -0.629952 -0.758951 +vn 0.186022 -0.822528 -0.537441 +vn 0.987315 0.117179 -0.107136 +vn 0.996495 0.082030 -0.016392 +vn 0.972378 0.207707 0.106487 +vn 0.953688 0.174311 0.245144 +vn -0.033524 0.819839 0.571612 +vn -0.982575 -0.118182 0.143455 +vn -0.986712 -0.160483 -0.025373 +vn -0.949829 -0.278586 -0.142180 +vn -0.941935 -0.238071 -0.236814 +vn -0.957691 -0.287109 0.019907 +vn -0.950876 -0.300224 -0.075502 +vn -0.991824 -0.117375 -0.050085 +vn -0.994509 -0.104383 0.007543 +vn -0.206044 -0.060019 0.976700 +vn -0.046109 0.237667 0.970252 +vn 0.955564 0.263257 0.132636 +vn 0.996890 0.062398 0.048141 +vn 0.964846 0.250206 0.080431 +vn 0.983955 0.066133 0.165706 +vn 0.943815 0.265487 0.196800 +vn -0.183580 0.981916 -0.046262 +vn -0.174942 0.468114 0.866178 +vn -0.154040 0.694748 0.702565 +vn -0.991539 -0.098831 0.084161 +vn -0.194063 0.894732 0.402237 +vn -0.192284 0.616136 0.763809 +vn 0.007888 0.046794 0.998873 +vn -0.137128 0.267777 0.953673 +vn -0.037901 -0.035946 0.998635 +vn 0.035462 -0.506860 0.861299 +vn -0.038513 -0.621704 0.782305 +vn 0.125746 -0.880038 0.457953 +vn 0.223548 -0.973429 0.049633 +vn 0.184201 -0.982635 -0.022343 +vn 0.167071 -0.973864 0.153868 +vn -0.192284 0.616136 0.763809 +vn 0.007888 0.046794 0.998873 +vn -0.137128 0.267777 0.953673 +vn -0.037901 -0.035946 0.998635 +vn 0.035462 -0.506860 0.861299 +vn -0.038513 -0.621704 0.782305 +vn 0.223548 -0.973429 0.049633 +vn 0.184201 -0.982635 -0.022343 +vn 0.184004 -0.982235 -0.036844 +vn 0.173822 -0.703838 -0.688765 +vn 0.186411 -0.813115 -0.551448 +vn 0.190373 -0.877950 -0.439274 +vn 0.190122 -0.857053 -0.478868 +vn 0.974755 -0.126233 -0.184166 +vn 0.113474 0.435534 -0.892992 +vn 0.965168 0.235515 -0.113942 +vn -0.000215 0.855095 -0.518471 +vn -0.000139 0.326907 -0.945057 +vn -0.965282 0.235120 -0.113794 +vn 0.944755 0.190115 0.267009 +vn 0.000209 -0.788354 0.615222 +vn 0.930523 -0.307488 -0.198940 +vn -0.000016 -0.280221 -0.959935 +vn -0.930428 -0.307869 -0.198798 +vn -0.944792 0.189729 0.267153 +vn 0.000030 -0.473558 -0.880762 +vn -0.999215 0.012405 0.037636 +vn -0.000182 0.586000 -0.810311 +vn -0.965068 0.208566 -0.158566 +vn 0.018448 0.604201 -0.796618 +vn -0.997623 0.033150 -0.060411 +vn 0.033935 0.682995 -0.729635 +vn -0.999845 0.012291 0.012614 +vn 0.999215 0.012813 0.037483 +vn 0.963495 0.214943 -0.159614 +vn 0.999909 -0.010049 -0.008951 +vn 0.999823 0.013786 0.012814 +vn -0.019644 -0.701962 0.711944 +vn -0.016220 -0.710798 0.703209 +vn 0.000125 -0.251570 0.967839 +vn 0.000203 -0.743082 0.669200 +vn -0.009102 0.390558 0.920533 +vn -0.968641 0.206087 0.138789 +vn 0.000167 -0.490240 0.871587 +vn 0.969930 0.217054 0.110109 +vn 0.000014 0.284346 0.958722 +vn -0.000218 0.935654 -0.352919 +vn -0.000081 0.672442 0.740150 +vn -0.000215 0.855095 -0.518471 +vn -0.000184 0.978354 0.206938 +vn -0.984311 0.023871 0.174822 +vn -0.000000 0.735776 0.677225 +vn -0.994761 -0.102085 0.005409 +vn 0.000000 0.998778 0.049420 +vn 0.994765 -0.102045 0.005330 +vn 0.984311 0.023871 0.174822 +vn -0.000037 0.095394 0.995440 +vn 0.997592 0.000059 0.069352 +vn 0.997209 -0.018374 -0.072363 +vn 0.000000 0.868314 0.496015 +vn 0.952375 0.238892 -0.189504 +vn -0.000000 0.770234 -0.637761 +vn -0.000002 0.999938 -0.011129 +vn -0.952375 0.238892 -0.189504 +vn -0.997209 -0.018374 -0.072363 +vn -0.997592 0.000059 0.069352 +vn 0.000000 0.048821 0.998808 +vn -0.000001 -0.729710 0.683757 +vn 0.980792 0.194245 -0.017785 +vn -0.001413 0.920988 0.389589 +vn 0.981461 0.169038 0.090335 +vn 0.999655 0.019487 -0.017594 +vn 0.970216 -0.095718 -0.222529 +vn 0.952749 -0.301210 0.039263 +vn 0.992438 -0.116531 -0.038574 +vn -0.980771 0.194340 -0.017889 +vn -0.981922 0.166937 0.089223 +vn -0.999662 0.019314 -0.017379 +vn -0.969816 -0.096031 -0.224132 +vn -0.953156 -0.299808 0.040106 +vn -0.992481 -0.116054 -0.038886 +vn -0.000446 -0.853262 0.521483 +vn -0.003246 -0.934312 0.356442 +vn 0.000766 0.665270 -0.746603 +vn 0.002033 -0.128309 -0.991732 +vn 0.001551 -0.874211 -0.485544 +vn 0.000100 -0.999353 -0.035969 +vn 0.999228 0.039236 -0.001790 +vn 0.999237 0.039022 -0.001786 +vn 0.999999 0.000408 0.000946 +vn 0.999999 0.000241 0.000997 +vn 0.999237 0.038925 0.003243 +vn 0.999227 0.039168 0.003245 +vn 0.997024 0.077013 -0.003433 +vn 0.999422 0.005647 -0.033524 +vn 0.000001 0.996047 0.088823 +vn -0.000000 0.973312 0.229487 +vn -0.999422 0.005648 -0.033527 +vn -0.997024 0.077015 -0.003434 +vn 0.000001 0.948899 -0.315579 +vn -0.941514 0.136303 -0.308178 +vn 0.000001 0.579012 -0.815319 +vn -0.000000 -0.327881 -0.944719 +vn -0.962139 -0.186614 0.198655 +vn -0.000001 -0.863781 -0.503868 +vn -0.000001 -0.865076 0.501641 +vn 0.962139 -0.186616 0.198655 +vn 0.941514 0.136301 -0.308178 +vn -0.000001 -0.999324 0.036775 +vn -0.000000 -0.400820 0.916157 +vn 0.000001 0.880052 0.474878 +vn 0.000000 0.458522 0.888683 +vn -0.000000 -0.929689 -0.368345 +vn -0.999144 0.026973 -0.031351 +vn 0.999144 0.026973 -0.031350 +vn -0.000000 0.917435 -0.397885 +vn -0.000037 0.095394 0.995440 +vn 0.997592 0.000059 0.069352 +vn 0.996939 -0.064519 -0.044167 +vn 0.992029 -0.115412 -0.050582 +vn 0.999948 -0.002072 0.009978 +vn 0.000000 -0.159289 -0.987232 +vn 0.997443 0.026637 0.066311 +vn 0.000000 -0.468004 -0.883727 +vn -0.000000 -0.522693 -0.852521 +vn -0.997443 0.026637 0.066311 +vn -0.999948 -0.002072 0.009978 +vn -0.992029 -0.115412 -0.050582 +vn -0.995590 -0.092254 -0.017041 +vn 0.989368 0.126324 0.072067 +vn 0.000000 0.985242 0.171166 +vn 0.009155 0.997730 -0.066710 +vn -0.989368 0.126325 0.072064 +vn -0.996939 -0.064519 -0.044167 +vn -0.997592 0.000059 0.069352 +vn 0.000000 0.868314 0.496015 +vn 0.000000 0.462568 0.886584 +vn -0.000000 -0.027511 0.999622 +vn -0.943336 0.286153 0.168027 +vn 0.943336 0.286153 0.168027 +vn -0.000000 0.971305 -0.237836 +vn -0.000000 0.225981 0.974132 +vn -0.000000 -0.561054 0.827779 +vn -0.000004 -0.911856 0.410509 +vn 0.993321 0.042025 -0.107458 +vn -0.000000 -0.021451 0.999770 +vn 0.997163 -0.034360 -0.066974 +vn 0.000001 0.115355 -0.993324 +vn -0.993321 0.042034 -0.107458 +vn 0.000002 0.524091 -0.851662 +vn -0.997163 -0.034351 -0.066973 +vn -0.999850 -0.007807 -0.015490 +vn 0.000002 0.413481 0.910513 +vn 0.000001 0.289044 0.957316 +vn -0.955476 0.290352 0.052548 +vn -0.000004 -0.919805 0.392375 +vn 0.000000 0.080606 0.996746 +vn 0.955479 0.290343 0.052548 +vn 0.000001 0.335195 -0.942149 +vn 0.999849 -0.007816 -0.015490 +vn 0.000004 0.976656 -0.214810 +vn 0.000005 0.998432 0.055981 +vn 0.999662 0.025907 -0.002029 +vn -0.000003 -0.747647 -0.664097 +vn -0.000003 -0.751333 -0.659924 +vn -0.999662 0.025913 -0.002030 +vn 0.000003 0.755855 -0.654739 +vn 0.000004 0.943668 0.330894 +vn 0.000002 -0.964340 -0.264665 +vn 0.995590 -0.092254 -0.017041 +vn -0.000002 -0.894833 -0.446401 +vn -0.000003 -0.740303 -0.672273 +vn 0.000003 0.936366 0.351025 +vn -0.000001 0.005223 -0.999986 +vn -0.982773 0.102315 -0.153910 +vn 0.000000 0.910810 0.412826 +vn 0.000000 0.906736 0.421700 +vn 0.982773 0.102315 -0.153910 +vn 0.000000 -0.943161 -0.332337 +vn -0.000000 -0.127710 -0.991812 +vn 0.000001 0.825057 -0.565049 +vn 0.992561 -0.121730 0.001914 +vn 0.000083 -0.887428 0.460945 +vn 0.986925 -0.160498 -0.014816 +vn 0.000000 -0.894497 -0.447073 +vn 0.000000 -0.929703 -0.368311 +vn 0.000000 -0.907717 -0.419582 +vn -0.986925 -0.160498 -0.014816 +vn -0.991922 -0.126825 -0.002437 +vn 0.984468 0.046512 0.169293 +vn -0.018090 -0.998012 -0.060374 +vn 0.990540 -0.127428 -0.050915 +vn -0.000192 -0.963186 0.268836 +vn 0.968639 -0.211977 0.129633 +vn -0.001094 -0.465463 0.885067 +vn -0.003288 -0.183180 0.983074 +vn -0.969199 -0.210347 0.128089 +vn -0.988222 -0.134888 -0.072270 +vn -0.984216 0.133285 0.116421 +vn -0.086856 0.528456 0.844506 +vn 0.002062 0.664510 0.747276 +vn 0.001993 0.777780 -0.628534 +vn 0.090354 0.975614 -0.200033 +vn -0.997506 0.026746 -0.065311 +vn 0.010690 -0.340925 -0.940030 +vn 0.998169 0.025353 -0.054923 +vn -0.003507 0.308319 0.951277 +vn -0.978782 0.194368 -0.064857 +vn 0.000701 -0.121937 -0.992538 +vn 0.978572 0.197330 -0.058809 +vn -0.002347 0.903631 0.428304 +vn 0.001533 0.966922 -0.255067 +vn -0.977747 0.209138 0.016476 +vn -0.924680 0.380713 -0.004889 +vn -0.421020 -0.757608 -0.498771 +vn -0.326267 -0.677363 0.659340 +vn 0.044040 0.866512 0.497210 +vn 0.003460 0.467918 0.883765 +vn -0.126530 -0.035200 0.991338 +vn -0.605948 -0.230040 0.761518 +vn 0.896868 -0.441527 0.026115 +vn -0.126530 -0.035200 0.991338 +vn 0.977200 -0.212087 -0.009945 +vn 0.003460 0.467918 0.883765 +vn 0.044040 0.866512 0.497210 +vn 0.075652 0.981135 0.177909 +vn 0.976613 -0.206429 -0.060110 +vn -0.067053 0.996342 -0.052971 +vn 0.018406 0.984898 0.172152 +vn 0.969369 -0.172616 -0.174719 +vn -0.058088 0.973662 -0.220471 +vn -0.365642 -0.800398 -0.475046 +vn -0.459781 -0.770704 -0.441153 +vn -0.430318 -0.836867 -0.338350 +vn -0.373633 -0.546006 -0.749850 +vn -0.215864 0.158093 -0.963540 +vn -0.973629 0.181660 0.138008 +vn -0.977204 0.205235 0.054318 +vn -0.150713 0.767596 -0.622962 +vn -0.058088 0.973662 -0.220471 +vn 0.018406 0.984898 0.172152 +vn -0.067053 0.996342 -0.052971 +vn 0.075652 0.981135 0.177909 +vn -0.977202 -0.212077 -0.009946 +vn -0.896872 -0.441518 0.026115 +vn 0.421011 -0.757613 -0.498772 +vn 0.326261 -0.677365 0.659341 +vn -0.003459 0.467918 0.883765 +vn 0.977749 0.209128 0.016477 +vn 0.126530 -0.035201 0.991338 +vn 0.924684 0.380704 -0.004889 +vn 0.605946 -0.230045 0.761517 +vn 0.126530 -0.035201 0.991338 +vn -0.003459 0.467918 0.883765 +vn -0.044028 0.866512 0.497210 +vn -0.075648 0.981135 0.177908 +vn -0.976615 -0.206419 -0.060110 +vn 0.067064 0.996342 -0.052970 +vn -0.018394 0.984898 0.172153 +vn -0.969371 -0.172606 -0.174719 +vn 0.058096 0.973662 -0.220471 +vn 0.150719 0.767594 -0.622963 +vn 0.365633 -0.800401 -0.475048 +vn 0.977206 0.205225 0.054318 +vn 0.459774 -0.770709 -0.441153 +vn 0.430310 -0.836871 -0.338349 +vn 0.973631 0.181651 0.138009 +vn 0.373628 -0.546011 -0.749850 +vn 0.215867 0.158090 -0.963540 +vn 0.058096 0.973662 -0.220471 +vn -0.018394 0.984898 0.172153 +vn 0.067064 0.996342 -0.052970 +vn -0.075648 0.981135 0.177908 +vn -0.044028 0.866512 0.497210 +vn -0.999227 -0.039168 -0.003245 +vn -0.999237 -0.038925 -0.003243 +vn -0.999999 -0.000408 -0.000946 +vn -0.999999 -0.000241 -0.000997 +vn -0.999237 -0.039021 0.001786 +vn -0.999228 -0.039236 0.001790 +vn -0.930428 -0.307869 -0.198798 +vn 0.000160 -0.924827 -0.380387 +vn 0.000206 -0.767778 0.640716 +vn 0.930523 -0.307488 -0.198940 +vn 0.000076 0.001234 0.999999 +vn 0.974203 -0.093010 -0.205615 +vn 0.974311 -0.092994 -0.205111 +vn 0.974515 -0.092605 -0.204314 +vn 0.974509 -0.092587 -0.204352 +vn 0.974770 -0.092093 -0.203328 +vn 0.974718 -0.092075 -0.203586 +vn 0.975033 -0.091473 -0.202342 +vn 0.974909 -0.091490 -0.202932 +vn -0.974128 -0.092926 -0.206006 +vn -0.974030 -0.093326 -0.206289 +vn -0.974255 -0.092906 -0.205417 +vn -0.974088 -0.093332 -0.206013 +vn -0.973911 -0.093662 -0.206700 +vn -0.973921 -0.093672 -0.206647 +vn -0.973791 -0.093916 -0.207147 +vn -0.973681 -0.093934 -0.207660 +vn 0.942782 0.292417 0.160170 +vn 0.944467 0.294284 0.146214 +vn 0.942564 0.296394 0.154025 +vn 0.943993 0.298346 0.140947 +vn 0.942817 0.299685 0.145897 +vn 0.944360 0.301657 0.131097 +vn 0.943968 0.302227 0.132606 +vn 0.945773 0.304759 0.112409 +vn -0.939976 0.337106 0.052951 +vn -0.942567 0.306822 0.132017 +vn -0.938636 0.313675 0.143424 +vn -0.940964 0.301670 0.153565 +vn -0.944049 0.298176 0.140934 +vn -0.942634 0.296242 0.153890 +vn -0.944540 0.294126 0.146064 +vn -0.942892 0.292299 0.159735 +vn 0.000001 0.144996 -0.989432 +vn -0.992317 0.054838 -0.110904 +vn 0.000005 0.905209 -0.424967 +vn 0.000002 0.451631 -0.892205 +vn 0.992318 0.054827 -0.110904 +vn -0.000005 -0.874960 0.484196 +vn -0.980257 -0.171150 0.099013 +vn -0.926163 0.177451 -0.332766 +vn -0.000002 -0.434343 -0.900748 +vn 0.000003 0.674424 -0.738344 +vn 0.926165 0.177442 -0.332765 +vn 0.980255 -0.171160 0.099013 +vn -0.000002 -0.311792 0.950150 +vn -0.929757 -0.337552 -0.147005 +vn -0.000002 -0.340097 -0.940390 +vn 0.929754 -0.337561 -0.147005 +vn -0.000005 -0.937196 0.348803 +vn 0.000004 0.815440 0.578842 +vn -0.994727 0.102546 -0.001517 +vn 0.000002 0.432076 0.901837 +vn -0.820215 0.395485 0.413328 +vn 0.000004 0.888771 -0.458352 +vn 0.000002 0.444680 -0.895690 +vn 0.820218 0.395476 0.413328 +vn 0.994728 0.102536 -0.001517 +vn 0.000005 0.962464 0.271411 +vn 0.000002 0.425711 0.904859 +vn 0.000004 0.708160 0.706052 +vn 0.000005 0.987678 -0.156499 +vn 0.000002 0.722443 0.691431 +vn -0.994929 0.025472 0.097298 +vn 0.000004 0.695704 0.718328 +vn 0.000004 0.803174 0.595744 +vn 0.994929 0.025463 0.097298 +vn -0.000004 -0.786440 -0.617667 +vn -0.000004 -0.953480 -0.301457 +vn 0.962434 -0.024639 -0.270395 +vn -0.000003 -0.767982 -0.640472 +vn 0.000002 0.558287 -0.829648 +vn -0.962434 -0.024631 -0.270396 +vn 0.000002 0.886009 -0.463668 +vn -0.000004 -0.772346 -0.635202 +vn -0.000005 -0.983228 -0.182379 +vn -0.000008 -0.999896 0.014417 +vn -0.000000 -0.977753 -0.209761 +vn 0.000002 -0.410412 0.911900 +vn -0.000000 -0.840484 -0.541837 +vn -0.066720 0.763639 0.642187 +vn -0.997954 0.061290 0.018221 +vn 0.003126 0.881272 0.472598 +vn 0.119530 0.758895 -0.640149 +vn 0.999696 0.011500 0.021827 +vn -0.001413 0.920988 0.389589 +vn 0.999655 0.019487 -0.017594 +vn 0.977282 0.205556 0.051630 +vn 0.998437 -0.004917 0.055677 +vn 0.005768 0.332013 0.943257 +vn 0.028061 0.996278 -0.081507 +vn -0.997967 0.021874 0.059868 +vn -0.977438 0.206054 0.046438 +vn -0.999662 0.019314 -0.017379 +vn 0.001364 0.943949 -0.330088 +vn 0.000035 0.995202 -0.097845 +vn -0.000921 0.600915 0.799312 +vn -0.003246 -0.934312 0.356442 +vn 0.845666 -0.524898 -0.096596 +vn 0.952749 -0.301210 0.039263 +vn -0.012196 -0.923558 0.383265 +vn -0.014969 -0.965380 0.260419 +vn -0.004647 -0.790319 -0.612678 +vn -0.991422 -0.125728 0.035697 +vn 0.003917 0.062553 -0.998034 +vn -0.977080 -0.189475 0.097024 +vn 0.001953 0.415009 -0.909815 +vn 0.000197 -0.824192 -0.566311 +vn 0.976711 -0.189511 0.100607 +vn 0.991422 -0.122358 0.045938 +vn -0.002174 0.011420 0.999932 +vn -0.006970 -0.150529 0.988581 +vn -0.999924 0.011784 0.003661 +vn -0.000161 0.830537 -0.556963 +vn 0.998740 0.048629 -0.012374 +vn -0.004775 -0.853647 0.520831 +vn 0.000122 -0.705679 0.708531 +vn 0.298803 0.427104 0.853405 +vn -0.922271 0.236722 0.305580 +vn 0.305543 0.473813 0.825921 +vn 0.128589 0.990414 -0.050456 +vn 0.970112 -0.020777 -0.241766 +vn -0.184541 0.480444 -0.857390 +vn -0.080753 0.775774 -0.625822 +vn 0.283218 0.022299 0.958796 +vn 0.282380 0.324925 0.902599 +vn 0.977131 -0.138658 -0.161209 +vn 0.427407 0.469488 0.772596 +vn 0.297772 0.568798 0.766681 +vn 0.991217 0.051292 -0.121892 +vn 0.908397 -0.192369 -0.371226 +vn 0.927985 -0.120518 -0.352590 +vn 0.189927 0.963438 0.188985 +vn -0.970697 0.135155 0.198696 +vn -0.984809 0.049160 0.166539 +vn -0.911086 0.109395 0.397435 +vn 0.016448 -0.879180 0.476206 +vn 0.205260 -0.511068 0.834672 +vn 0.300518 0.125220 0.945520 +vn 0.205260 -0.511068 0.834672 +vn 0.016448 -0.879180 0.476206 +vn -0.031983 -0.949803 0.311209 +vn -0.030933 -0.976969 0.211128 +vn -0.293879 -0.365185 -0.883332 +vn -0.287325 -0.168596 -0.942878 +vn -0.286973 -0.165960 -0.943453 +vn -0.266090 -0.754517 -0.599917 +vn -0.978461 0.198257 0.057521 +vn -0.296490 -0.332614 -0.895244 +vn -0.226240 -0.903633 -0.363681 +vn 0.849260 -0.029821 -0.527133 +vn -0.307595 -0.445785 -0.840632 +vn -0.160557 0.709528 -0.686142 +vn 0.186119 0.970223 0.155006 +vn 0.165725 0.986172 -0.000257 +vn -0.043424 0.828368 -0.558499 +vn 0.186119 0.970223 0.155006 +vn 0.086528 0.773543 -0.627809 +vn 0.920099 0.238506 0.310697 +vn 0.188154 0.479650 -0.857049 +vn -0.128623 0.990571 -0.047177 +vn -0.969176 -0.020258 -0.245533 +vn -0.310495 0.466956 0.827976 +vn -0.307207 0.415973 0.855915 +vn -0.292348 0.028946 0.955874 +vn -0.286649 0.328135 0.900089 +vn 0.907830 0.112333 0.404012 +vn -0.437335 0.459955 0.772774 +vn -0.302847 0.565840 0.766882 +vn 0.852066 0.299026 0.429612 +vn 0.984417 0.049957 0.168607 +vn 0.970178 0.135955 0.200677 +vn -0.190756 0.963182 0.189453 +vn -0.926005 -0.121196 -0.357529 +vn -0.905369 -0.194817 -0.377298 +vn -0.976551 -0.140341 -0.163254 +vn -0.017370 -0.876438 0.481201 +vn -0.209330 -0.503481 0.838265 +vn -0.305855 0.131529 0.942949 +vn -0.209330 -0.503481 0.838265 +vn -0.017370 -0.876438 0.481201 +vn 0.032082 -0.948887 0.313982 +vn 0.031168 -0.976414 0.213646 +vn 0.300173 -0.363528 -0.881898 +vn 0.291877 -0.170474 -0.941141 +vn 0.293474 -0.167282 -0.941217 +vn 0.269261 -0.752025 -0.601629 +vn -0.845800 -0.029787 -0.532668 +vn 0.300483 -0.334382 -0.893252 +vn 0.228349 -0.904183 -0.360983 +vn 0.978007 0.199697 0.060190 +vn 0.311373 -0.443809 -0.840286 +vn 0.162272 0.710777 -0.684444 +vn -0.187369 0.969806 0.156105 +vn -0.165766 0.986160 -0.003038 +vn 0.046038 0.826865 -0.560513 +vn -0.187369 0.969806 0.156105 +vn 0.282380 0.324925 0.902599 +vn 0.427407 0.469488 0.772596 +vn -0.856679 0.296375 0.422212 +vn 0.083537 0.982162 0.168464 +vn -0.111471 0.957371 0.266486 +vn -0.286649 0.328135 0.900089 +vn -0.437335 0.459955 0.772774 +vn -0.991012 0.051873 -0.123308 +vn -0.001454 -0.422566 0.906331 +vn -0.001087 -0.743490 0.668746 +vn -0.000446 -0.853262 0.521483 +vn -0.992481 -0.116054 -0.038886 +vn 0.000766 0.665270 -0.746603 +vn 0.992438 -0.116531 -0.038574 +vn -0.845293 -0.525517 -0.096495 +vn 0.000758 -0.994137 -0.108121 +vn -0.953156 -0.299808 0.040106 +vn 0.078211 -0.996664 0.023330 +vn -0.107788 -0.702985 0.702989 +vn 0.074009 -0.996907 0.026457 +vn -0.109573 -0.705459 0.700230 +vn -0.228254 0.033980 0.973008 +vn -0.228776 0.021472 0.973242 +vn -0.208635 0.736277 0.643713 +vn -0.212135 0.727111 0.652922 +vn -0.079149 0.996180 -0.036877 +vn -0.083840 0.996085 -0.028028 +vn 0.094230 0.701879 -0.706036 +vn 0.091586 0.705163 -0.703105 +vn 0.220479 -0.026697 -0.975026 +vn 0.220146 -0.028159 -0.975060 +vn 0.212450 -0.727114 -0.652817 +vn 0.210441 -0.730095 -0.650136 +vn 0.078211 -0.996664 0.023330 +vn 0.074009 -0.996907 0.026457 +vn -0.312078 -0.945872 -0.089073 +vn -0.142242 -0.769986 0.622004 +vn -0.312580 -0.945197 -0.094322 +vn -0.143530 -0.774119 0.616554 +vn 0.085613 -0.224935 0.970605 +vn 0.060859 -0.264296 0.962520 +vn 0.047299 0.436942 0.898245 +vn 0.039550 0.568150 0.821974 +vn 0.207973 0.970794 0.119613 +vn 0.246010 0.969062 0.019955 +vn 0.132295 0.790427 -0.598100 +vn 0.131946 0.759473 -0.637017 +vn -0.113872 0.141942 -0.983303 +vn -0.113885 0.139911 -0.983593 +vn -0.305043 -0.587451 -0.749566 +vn -0.305144 -0.587556 -0.749443 +vn -0.312078 -0.945872 -0.089073 +vn -0.312580 -0.945197 -0.094322 +vn -0.075472 -0.996929 0.020894 +vn -0.077631 -0.996627 0.026608 +vn -0.197624 -0.730106 -0.654133 +vn -0.199227 -0.731429 -0.652166 +vn -0.201368 -0.027050 -0.979142 +vn -0.201260 -0.025887 -0.979196 +vn -0.077031 0.705131 -0.704881 +vn -0.077387 0.706758 -0.703210 +vn 0.082615 0.996044 -0.032725 +vn 0.080353 0.996278 -0.031200 +vn 0.192557 0.733429 0.651924 +vn 0.189938 0.736291 0.649461 +vn 0.200772 0.019960 0.979435 +vn 0.200743 0.031303 0.979144 +vn 0.089543 -0.711681 0.696773 +vn 0.089935 -0.704268 0.704214 +vn -0.075472 -0.996929 0.020894 +vn -0.077631 -0.996627 0.026608 +vn 0.312578 -0.945197 -0.094321 +vn 0.312077 -0.945872 -0.089074 +vn 0.305143 -0.587556 -0.749444 +vn 0.305043 -0.587451 -0.749567 +vn 0.113841 0.140044 -0.983579 +vn 0.113918 0.142095 -0.983276 +vn -0.131591 0.759895 -0.636588 +vn -0.131698 0.790723 -0.597840 +vn -0.252496 0.966355 0.049037 +vn -0.248964 0.957952 0.142632 +vn -0.321444 0.625529 0.710906 +vn -0.303778 0.587894 0.749733 +vn -0.118140 -0.158620 0.980246 +vn -0.119774 -0.121165 0.985380 +vn 0.143512 -0.774142 0.616530 +vn 0.142249 -0.770011 0.621971 +vn 0.312578 -0.945197 -0.094321 +vn 0.312077 -0.945872 -0.089074 +vn -0.974756 -0.126233 -0.184165 +vn -0.013724 0.310133 -0.950594 +vn 0.071186 -0.030537 -0.996996 +vn 0.134327 -0.069796 -0.988476 +vn 0.060284 0.003901 -0.998174 +vn 0.134327 -0.069796 -0.988476 +vn -0.013724 0.310133 -0.950594 +vn 0.948949 0.285527 -0.134052 + +vt 0.860815 0.982957 +vt 0.462668 0.976864 +vt 0.462668 0.976864 +vt 0.860815 0.982957 +vt 0.452339 0.873155 +vt 0.449359 0.829309 +vt 0.469503 0.827865 +vt 0.446731 0.790634 +vt 0.449102 0.825518 +vt 0.369801 0.809341 +vt 0.430594 0.759531 +vt 0.427255 0.720797 +vt 0.366672 0.724056 +vt 0.407393 0.707588 +vt 0.405326 0.685241 +vt 0.361864 0.648753 +vt 0.366672 0.724056 +vt 0.407187 0.707718 +vt 0.369801 0.809341 +vt 0.430867 0.759468 +vt 0.449386 0.829706 +vt 0.297366 0.639258 +vt 0.271826 0.735052 +vt 0.286243 0.822144 +vt 0.357286 0.880700 +vt 0.298058 0.900570 +vt 0.408541 0.972989 +vt 0.349441 0.982878 +vt 0.298058 0.900570 +vt 0.357286 0.880700 +vt 0.286243 0.822144 +vt 0.271826 0.735052 +vt 0.427434 0.897073 +vt 0.449652 0.943908 +vt 0.427071 0.896628 +vt 0.452105 0.872920 +vt 0.315954 0.970018 +vt 0.303012 0.993358 +vt 0.264433 0.977986 +vt 0.077868 0.795956 +vt 0.179999 0.736810 +vt 0.126370 0.838250 +vt 0.204881 0.830636 +vt 0.256089 0.938174 +vt 0.204881 0.830636 +vt 0.179999 0.736810 +vt 0.126370 0.838250 +vt 0.077868 0.795956 +vt 0.082745 0.888427 +vt 0.162255 0.939340 +vt 0.191264 0.916350 +vt 0.220495 0.939611 +vt 0.119206 0.665880 +vt 0.087455 0.676944 +vt 0.055321 0.693406 +vt 0.024008 0.718360 +vt 0.021729 0.757727 +vt 0.007706 0.836107 +vt 0.015481 0.885625 +vt 0.033721 0.897043 +vt 0.036091 0.921392 +vt 0.067450 0.942231 +vt 0.113305 0.950841 +vt 0.082745 0.888427 +vt 0.067624 0.942121 +vt 0.038029 0.920452 +vt 0.034255 0.896373 +vt 0.016103 0.885193 +vt 0.007700 0.836110 +vt 0.020223 0.757373 +vt 0.055674 0.693974 +vt 0.087506 0.677064 +vt 0.137251 0.637233 +vt 0.175766 0.638736 +vt 0.252190 0.652907 +vt 0.223643 0.643080 +vt 0.199175 0.653268 +vt 0.446731 0.790634 +vt 0.469301 0.828341 +vt 0.448982 0.825104 +vt 0.452105 0.872920 +vt 0.452339 0.873155 +vt 0.469503 0.827865 +vt 0.449359 0.829309 +vt 0.369801 0.809341 +vt 0.427434 0.897073 +vt 0.357286 0.880700 +vt 0.449652 0.943908 +vt 0.408541 0.972989 +vt 0.357286 0.880700 +vt 0.427071 0.896628 +vt 0.369801 0.809341 +vt 0.361864 0.648753 +vt 0.297366 0.639258 +vt 0.366672 0.724056 +vt 0.271826 0.735052 +vt 0.286243 0.822144 +vt 0.298058 0.900570 +vt 0.349441 0.982878 +vt 0.298058 0.900570 +vt 0.286243 0.822144 +vt 0.271826 0.735052 +vt 0.366672 0.724056 +vt 0.077868 0.795956 +vt 0.179999 0.736810 +vt 0.126370 0.838250 +vt 0.204881 0.830636 +vt 0.256089 0.938174 +vt 0.264433 0.977986 +vt 0.204881 0.830636 +vt 0.179999 0.736810 +vt 0.126370 0.838250 +vt 0.077868 0.795956 +vt 0.082745 0.888427 +vt 0.162255 0.939340 +vt 0.191264 0.916350 +vt 0.220495 0.939611 +vt 0.082745 0.888427 +vt 0.113305 0.950841 +vt 0.067624 0.942121 +vt 0.038029 0.920452 +vt 0.034255 0.896373 +vt 0.016103 0.885193 +vt 0.007700 0.836110 +vt 0.020223 0.757373 +vt 0.024008 0.718360 +vt 0.055674 0.693974 +vt 0.087506 0.677064 +vt 0.119206 0.665880 +vt 0.067450 0.942231 +vt 0.036091 0.921392 +vt 0.033721 0.897043 +vt 0.015481 0.885625 +vt 0.007706 0.836107 +vt 0.021729 0.757727 +vt 0.055321 0.693406 +vt 0.087455 0.676944 +vt 0.137251 0.637233 +vt 0.175766 0.638736 +vt 0.252190 0.652907 +vt 0.223643 0.643080 +vt 0.199175 0.653268 +vt 0.448982 0.825104 +vt 0.469301 0.828341 +vt 0.201283 0.122248 +vt 0.181052 0.135861 +vt 0.209376 0.152034 +vt 0.201283 0.122248 +vt 0.188538 0.088750 +vt 0.221887 0.105024 +vt 0.235783 0.135619 +vt 0.234964 0.156276 +vt 0.235783 0.135619 +vt 0.188538 0.088750 +vt 0.215262 0.099750 +vt 0.265698 0.058372 +vt 0.253736 0.075406 +vt 0.354850 0.068903 +vt 0.376683 0.139264 +vt 0.429197 0.141490 +vt 0.408012 0.188476 +vt 0.519860 0.250479 +vt 0.265698 0.058372 +vt 0.354850 0.068903 +vt 0.429197 0.141490 +vt 0.519860 0.250479 +vt 0.480438 0.133922 +vt 0.441285 0.072445 +vt 0.222289 0.038479 +vt 0.293134 0.025426 +vt 0.370019 0.040801 +vt 0.398642 0.056393 +vt 0.404400 0.032643 +vt 0.398642 0.056393 +vt 0.174416 0.064364 +vt 0.372003 0.028906 +vt 0.385251 0.017476 +vt 0.176780 0.136153 +vt 0.157451 0.098830 +vt 0.942060 0.524908 +vt 0.923629 0.512424 +vt 0.877811 0.592568 +vt 0.873037 0.569918 +vt 0.877811 0.592568 +vt 0.942060 0.524908 +vt 0.884555 0.623812 +vt 0.969930 0.546158 +vt 0.953415 0.438640 +vt 0.983334 0.448498 +vt 0.958784 0.377441 +vt 0.981510 0.388078 +vt 0.988818 0.300033 +vt 0.958784 0.377441 +vt 0.953415 0.438640 +vt 0.969930 0.546158 +vt 0.929856 0.438419 +vt 0.931701 0.372726 +vt 0.960702 0.294367 +vt 0.982544 0.213638 +vt 0.949968 0.216617 +vt 0.954690 0.123729 +vt 0.924384 0.140162 +vt 0.893410 0.063850 +vt 0.854283 0.081755 +vt 0.960702 0.294367 +vt 0.949968 0.216617 +vt 0.954690 0.123729 +vt 0.924384 0.140162 +vt 0.893410 0.063850 +vt 0.854283 0.081755 +vt 0.862680 0.050210 +vt 0.876710 0.056437 +vt 0.842458 0.112852 +vt 0.894962 0.160149 +vt 0.918543 0.225773 +vt 0.928622 0.297729 +vt 0.860815 0.982957 +vt 0.860879 0.980221 +vt 0.658740 0.979822 +vt 0.658804 0.977087 +vt 0.462733 0.974130 +vt 0.462668 0.976864 +vt 0.497082 0.505370 +vt 0.470706 0.464975 +vt 0.512230 0.486476 +vt 0.491394 0.451456 +vt 0.470706 0.464975 +vt 0.497082 0.505370 +vt 0.519701 0.508838 +vt 0.498307 0.541409 +vt 0.518103 0.541780 +vt 0.507916 0.563983 +vt 0.478235 0.558669 +vt 0.491266 0.576761 +vt 0.469583 0.577883 +vt 0.478235 0.558669 +vt 0.498307 0.541409 +vt 0.477078 0.511804 +vt 0.479123 0.532834 +vt 0.465455 0.545431 +vt 0.449993 0.562501 +vt 0.455530 0.476401 +vt 0.439755 0.438735 +vt 0.439755 0.438735 +vt 0.460622 0.424277 +vt 0.173284 0.322072 +vt 0.253675 0.411916 +vt 0.142280 0.356789 +vt 0.238422 0.444599 +vt 0.365015 0.430537 +vt 0.377390 0.461554 +vt 0.398210 0.430421 +vt 0.397064 0.464615 +vt 0.430578 0.460091 +vt 0.398210 0.430421 +vt 0.365015 0.430537 +vt 0.238422 0.444599 +vt 0.330961 0.533249 +vt 0.123976 0.299489 +vt 0.161442 0.265308 +vt 0.150061 0.210753 +vt 0.123976 0.299489 +vt 0.142280 0.356789 +vt 0.253675 0.411916 +vt 0.356497 0.404799 +vt 0.401170 0.398452 +vt 0.438296 0.414508 +vt 0.449692 0.423333 +vt 0.449692 0.423333 +vt 0.456259 0.409379 +vt 0.440323 0.406093 +vt 0.438756 0.413944 +vt 0.603255 0.661706 +vt 0.609337 0.675782 +vt 0.591535 0.678580 +vt 0.577549 0.693839 +vt 0.620440 0.684135 +vt 0.609337 0.675782 +vt 0.599617 0.702775 +vt 0.577549 0.693839 +vt 0.504615 0.676462 +vt 0.560658 0.671148 +vt 0.575913 0.683983 +vt 0.614763 0.656376 +vt 0.600510 0.663808 +vt 0.595270 0.654440 +vt 0.614763 0.656376 +vt 0.626434 0.661688 +vt 0.504615 0.676462 +vt 0.513830 0.646711 +vt 0.487735 0.628380 +vt 0.424123 0.622307 +vt 0.476830 0.699185 +vt 0.512932 0.713156 +vt 0.424123 0.622307 +vt 0.616372 0.644291 +vt 0.603839 0.643744 +vt 0.339498 0.611962 +vt 0.330961 0.533249 +vt 0.381983 0.651241 +vt 0.430538 0.680471 +vt 0.448007 0.578424 +vt 0.407711 0.546110 +vt 0.390872 0.523646 +vt 0.402247 0.499022 +vt 0.422604 0.507030 +vt 0.390872 0.523646 +vt 0.273175 0.538882 +vt 0.427505 0.541613 +vt 0.444779 0.521943 +vt 0.109051 0.232648 +vt 0.083389 0.291156 +vt 0.092857 0.322441 +vt 0.111552 0.374245 +vt 0.161457 0.443886 +vt 0.221622 0.491434 +vt 0.092857 0.322441 +vt 0.109051 0.232648 +vt 0.102832 0.179859 +vt 0.070997 0.187168 +vt 0.082668 0.171251 +vt 0.048043 0.154827 +vt 0.059105 0.124611 +vt 0.033595 0.111632 +vt 0.027252 0.057935 +vt 0.059105 0.124611 +vt 0.082668 0.171251 +vt 0.102832 0.179859 +vt 0.095749 0.157343 +vt 0.119337 0.149122 +vt 0.077809 0.116163 +vt 0.131745 0.176641 +vt 0.044550 0.056014 +vt 0.062206 0.051484 +vt 0.044550 0.056014 +vt 0.027390 0.040913 +vt 0.046503 0.040304 +vt 0.070440 0.034963 +vt 0.046503 0.040304 +vt 0.031423 0.026720 +vt 0.044368 0.024441 +vt 0.092184 0.473462 +vt 0.085357 0.410965 +vt 0.123871 0.414238 +vt 0.073031 0.382038 +vt 0.043780 0.556512 +vt 0.010346 0.484756 +vt 0.029826 0.422780 +vt 0.059237 0.405153 +vt 0.085357 0.410965 +vt 0.029970 0.422366 +vt 0.092184 0.473462 +vt 0.010371 0.484796 +vt 0.043607 0.555992 +vt 0.062919 0.578204 +vt 0.144149 0.534669 +vt 0.097332 0.582603 +vt 0.124651 0.610623 +vt 0.198945 0.579718 +vt 0.164666 0.622178 +vt 0.167424 0.461791 +vt 0.186773 0.502994 +vt 0.218579 0.531919 +vt 0.242485 0.574409 +vt 0.238791 0.603715 +vt 0.198945 0.579718 +vt 0.144149 0.534669 +vt 0.212303 0.619206 +vt 0.164736 0.622041 +vt 0.124074 0.608776 +vt 0.097106 0.582489 +vt 0.063063 0.578337 +vt 0.092184 0.473462 +vt 0.085357 0.410965 +vt 0.123871 0.414238 +vt 0.073031 0.382038 +vt 0.010346 0.484756 +vt 0.092184 0.473462 +vt 0.029826 0.422780 +vt 0.085357 0.410965 +vt 0.059237 0.405153 +vt 0.029970 0.422366 +vt 0.010371 0.484796 +vt 0.043607 0.555992 +vt 0.062919 0.578204 +vt 0.144149 0.534669 +vt 0.097332 0.582603 +vt 0.124651 0.610623 +vt 0.198945 0.579718 +vt 0.164666 0.622178 +vt 0.212303 0.619206 +vt 0.167424 0.461791 +vt 0.144149 0.534669 +vt 0.186773 0.502994 +vt 0.218579 0.531919 +vt 0.198945 0.579718 +vt 0.242485 0.574409 +vt 0.238791 0.603715 +vt 0.164736 0.622041 +vt 0.124074 0.608776 +vt 0.097106 0.582489 +vt 0.063063 0.578337 +vt 0.043780 0.556512 +vt 0.462668 0.976864 +vt 0.462733 0.974130 +vt 0.658740 0.979822 +vt 0.658804 0.977087 +vt 0.860879 0.980221 +vt 0.860815 0.982957 +vt 0.223643 0.136040 +vt 0.248396 0.141580 +vt 0.252501 0.120087 +vt 0.223643 0.136040 +vt 0.237732 0.106170 +vt 0.244423 0.371620 +vt 0.201221 0.314216 +vt 0.315561 0.381661 +vt 0.211263 0.243077 +vt 0.372964 0.338459 +vt 0.268666 0.199875 +vt 0.383006 0.267320 +vt 0.339804 0.209917 +vt 0.339804 0.209917 +vt 0.268666 0.199875 +vt 0.383006 0.267320 +vt 0.372964 0.338459 +vt 0.211263 0.243077 +vt 0.315561 0.381661 +vt 0.201221 0.314216 +vt 0.244423 0.371620 +vt 0.244423 0.371620 +vt 0.201221 0.314216 +vt 0.315561 0.381661 +vt 0.211263 0.243077 +vt 0.372964 0.338459 +vt 0.268666 0.199875 +vt 0.383006 0.267320 +vt 0.339804 0.209917 +vt 0.339804 0.209917 +vt 0.268666 0.199875 +vt 0.383006 0.267320 +vt 0.372964 0.338459 +vt 0.211263 0.243077 +vt 0.315561 0.381661 +vt 0.201221 0.314216 +vt 0.244423 0.371620 +vt 0.946112 0.900273 +vt 0.926468 0.923173 +vt 0.951707 0.915259 +vt 0.951708 0.948500 +vt 0.926468 0.923173 +vt 0.904662 0.933631 +vt 0.901602 0.871544 +vt 0.952673 0.875391 +vt 0.966862 0.905163 +vt 0.995890 0.893312 +vt 0.952673 0.875391 +vt 0.901602 0.871544 +vt 0.906519 0.962866 +vt 0.921006 0.962545 +vt 0.930325 0.977334 +vt 0.921006 0.962545 +vt 0.898162 0.986386 +vt 0.884998 0.831661 +vt 0.835055 0.828730 +vt 0.914089 0.843480 +vt 0.944675 0.855456 +vt 0.970105 0.857921 +vt 0.974990 0.849329 +vt 0.944675 0.855456 +vt 0.835055 0.828730 +vt 0.979945 0.866797 +vt 0.955076 0.836404 +vt 0.965292 0.835693 +vt 0.975999 0.838377 +vt 0.667645 0.725855 +vt 0.628690 0.749921 +vt 0.723116 0.744267 +vt 0.830795 0.793572 +vt 0.628690 0.749921 +vt 0.544827 0.751393 +vt 0.600082 0.793323 +vt 0.653325 0.798129 +vt 0.637357 0.814577 +vt 0.703795 0.827290 +vt 0.653325 0.798129 +vt 0.679203 0.796895 +vt 0.826604 0.855738 +vt 0.883971 0.893810 +vt 0.066584 0.234763 +vt 0.051939 0.318367 +vt 0.039942 0.291274 +vt 0.078415 0.352487 +vt 0.518433 0.342852 +vt 0.596930 0.372356 +vt 0.495614 0.372346 +vt 0.509563 0.384431 +vt 0.596930 0.372356 +vt 0.704908 0.697230 +vt 0.762748 0.587288 +vt 0.635064 0.529882 +vt 0.664196 0.471462 +vt 0.570485 0.502966 +vt 0.532609 0.440972 +vt 0.664196 0.471462 +vt 0.635064 0.529882 +vt 0.762748 0.587288 +vt 0.585061 0.562643 +vt 0.556259 0.548111 +vt 0.532725 0.518955 +vt 0.891638 0.536453 +vt 0.834798 0.522182 +vt 0.863249 0.557196 +vt 0.740995 0.415292 +vt 0.710222 0.365459 +vt 0.670380 0.327664 +vt 0.648914 0.317618 +vt 0.686783 0.314011 +vt 0.677688 0.300925 +vt 0.701225 0.312146 +vt 0.708561 0.303169 +vt 0.677688 0.300925 +vt 0.648914 0.317618 +vt 0.665950 0.282992 +vt 0.638184 0.298500 +vt 0.581934 0.329264 +vt 0.471138 0.287636 +vt 0.581934 0.329264 +vt 0.594263 0.234570 +vt 0.541860 0.185080 +vt 0.823935 0.139298 +vt 0.764028 0.155462 +vt 0.867057 0.159722 +vt 0.891755 0.188019 +vt 0.764028 0.155462 +vt 0.857828 0.196936 +vt 0.808676 0.198863 +vt 0.732923 0.051895 +vt 0.777906 0.047831 +vt 0.706263 0.091941 +vt 0.789981 0.076590 +vt 0.809828 0.088776 +vt 0.786918 0.124643 +vt 0.673330 0.150676 +vt 0.742460 0.229581 +vt 0.839039 0.244042 +vt 0.742460 0.229581 +vt 0.673330 0.150676 +vt 0.706263 0.091941 +vt 0.609943 0.039704 +vt 0.661727 0.013981 +vt 0.706438 0.020887 +vt 0.661757 0.014034 +vt 0.609591 0.039395 +vt 0.577475 0.083758 +vt 0.546466 0.089004 +vt 0.674677 0.206586 +vt 0.642156 0.198204 +vt 0.618279 0.171453 +vt 0.686140 0.244512 +vt 0.766584 0.302276 +vt 0.582994 0.157093 +vt 0.552089 0.129609 +vt 0.766584 0.302276 +vt 0.740234 0.304354 +vt 0.781712 0.326659 +vt 0.790452 0.302620 +vt 0.794126 0.273587 +vt 0.818887 0.265766 +vt 0.790698 0.302733 +vt 0.808676 0.198863 +vt 0.764028 0.155462 +vt 0.857828 0.196936 +vt 0.891755 0.188019 +vt 0.764028 0.155462 +vt 0.867057 0.159722 +vt 0.823935 0.139298 +vt 0.732923 0.051895 +vt 0.777890 0.047887 +vt 0.706263 0.091941 +vt 0.790767 0.076062 +vt 0.809828 0.088776 +vt 0.786918 0.124643 +vt 0.673330 0.150676 +vt 0.742460 0.229581 +vt 0.839039 0.244042 +vt 0.742460 0.229581 +vt 0.673330 0.150676 +vt 0.706263 0.091941 +vt 0.609591 0.039395 +vt 0.661757 0.014034 +vt 0.706438 0.020887 +vt 0.661727 0.013981 +vt 0.609943 0.039704 +vt 0.577475 0.083758 +vt 0.546466 0.089004 +vt 0.674677 0.206586 +vt 0.642156 0.198204 +vt 0.618279 0.171453 +vt 0.686140 0.244512 +vt 0.766584 0.302276 +vt 0.582994 0.157093 +vt 0.552089 0.129609 +vt 0.766584 0.302276 +vt 0.740234 0.304354 +vt 0.781712 0.326659 +vt 0.790698 0.302733 +vt 0.794126 0.273587 +vt 0.818887 0.265766 +vt 0.790452 0.302620 +vt 0.777890 0.047887 +vt 0.790767 0.076062 +vt 0.786918 0.124643 +vt 0.315954 0.970018 +vt 0.303012 0.993358 +vt 0.777906 0.047831 +vt 0.789981 0.076590 +vt 0.786918 0.124643 +vt 0.687726 0.284568 +vt 0.697695 0.289284 +vt 0.786233 0.644241 +vt 0.797802 0.615177 +vt 0.811579 0.590016 +vt 0.797802 0.615177 +vt 0.834798 0.522182 +vt 0.851324 0.506406 +vt 0.863249 0.557196 +vt 0.516859 0.943675 +vt 0.554957 0.943664 +vt 0.516853 0.915385 +vt 0.554945 0.915372 +vt 0.593054 0.943641 +vt 0.593037 0.915350 +vt 0.631150 0.943610 +vt 0.631129 0.915321 +vt 0.669245 0.943576 +vt 0.669222 0.915287 +vt 0.707338 0.943542 +vt 0.707316 0.915253 +vt 0.745430 0.943513 +vt 0.745412 0.915223 +vt 0.783522 0.943491 +vt 0.783509 0.915199 +vt 0.821613 0.943479 +vt 0.821607 0.915188 +vt 0.516859 0.943675 +vt 0.554957 0.943664 +vt 0.516853 0.915385 +vt 0.554945 0.915372 +vt 0.593054 0.943641 +vt 0.593037 0.915350 +vt 0.631150 0.943610 +vt 0.631129 0.915321 +vt 0.669245 0.943576 +vt 0.669222 0.915287 +vt 0.707338 0.943542 +vt 0.707316 0.915253 +vt 0.745430 0.943513 +vt 0.745412 0.915223 +vt 0.783522 0.943491 +vt 0.783509 0.915199 +vt 0.821613 0.943479 +vt 0.821607 0.915188 +vt 0.821607 0.915188 +vt 0.821613 0.943479 +vt 0.783509 0.915199 +vt 0.783522 0.943491 +vt 0.745412 0.915223 +vt 0.745430 0.943513 +vt 0.707316 0.915253 +vt 0.707338 0.943542 +vt 0.669222 0.915287 +vt 0.669245 0.943576 +vt 0.631129 0.915321 +vt 0.631150 0.943610 +vt 0.593037 0.915350 +vt 0.593054 0.943641 +vt 0.554945 0.915372 +vt 0.554957 0.943664 +vt 0.516853 0.915385 +vt 0.516859 0.943675 +vt 0.821607 0.915188 +vt 0.821613 0.943479 +vt 0.783509 0.915199 +vt 0.783522 0.943491 +vt 0.745412 0.915223 +vt 0.745430 0.943513 +vt 0.707316 0.915253 +vt 0.707338 0.943542 +vt 0.669222 0.915287 +vt 0.669245 0.943576 +vt 0.631129 0.915321 +vt 0.631150 0.943610 +vt 0.593037 0.915350 +vt 0.593054 0.943641 +vt 0.554945 0.915372 +vt 0.554957 0.943664 +vt 0.516853 0.915385 +vt 0.516859 0.943675 +vt 0.449102 0.825518 +vt 0.430594 0.759531 +vt 0.427255 0.720797 +vt 0.407393 0.707588 +vt 0.405326 0.685241 +vt 0.407187 0.707718 +vt 0.430867 0.759468 +vt 0.449386 0.829706 + +g Ar_SmallBow_mimiyala_D +f 7/7/7 6/6/6 5/5/5 +f 6/6/6 7/7/7 8/8/8 +f 10/10/10 9/9/9 5/5/5 +f 9/9/9 10/10/10 8/8/8 +f 8/8/8 10/10/10 11/11/11 +f 11/11/11 10/10/10 12/12/12 +f 13/13/13 12/12/12 10/10/10 +f 12/12/12 13/13/13 14/14/14 +f 14/14/14 13/13/13 15/15/15 +f 16/16/16 15/15/15 13/13/13 +f 17/17/17 15/15/15 16/16/16 +f 15/15/15 17/17/17 18/18/18 +f 18/18/18 17/17/17 12/12/12 +f 19/19/19 12/12/12 17/17/17 +f 12/12/12 19/19/19 20/20/20 +f 20/20/20 19/19/19 8/8/8 +f 8/8/8 19/19/19 21/21/21 +f 5/5/5 21/21/21 19/19/19 +f 13/13/13 22/22/22 16/16/16 +f 22/22/22 13/13/13 23/23/23 +f 10/10/10 23/23/23 13/13/13 +f 23/23/23 10/10/10 24/24/24 +f 25/25/25 24/24/24 10/10/10 +f 24/24/24 25/25/25 26/26/26 +f 27/27/27 26/26/26 25/25/25 +f 26/26/26 27/27/27 28/28/28 +f 28/28/28 27/27/27 29/29/29 +f 30/30/30 29/29/29 27/27/27 +f 29/29/29 30/30/30 31/31/31 +f 19/19/19 31/31/31 30/30/30 +f 31/31/31 19/19/19 32/32/32 +f 17/17/17 32/32/32 19/19/19 +f 32/32/32 17/17/17 22/22/22 +f 16/16/16 22/22/22 17/17/17 +f 19/19/19 33/33/33 5/5/5 +f 30/30/30 33/33/33 19/19/19 +f 33/33/33 30/30/30 34/34/34 +f 27/27/27 34/34/34 30/30/30 +f 25/25/25 34/34/34 27/27/27 +f 34/34/34 25/25/25 35/35/35 +f 10/10/10 35/35/35 25/25/25 +f 35/35/35 10/10/10 36/36/36 +f 28/28/28 37/37/37 26/26/26 +f 38/38/38 26/26/26 37/37/37 +f 26/26/26 38/38/38 39/39/39 +f 39/39/39 38/38/38 29/29/29 +f 37/37/37 29/29/29 38/38/38 +f 29/29/29 37/37/37 28/28/28 +f 42/42/42 41/41/41 40/40/40 +f 43/43/43 41/41/41 42/42/42 +f 41/41/41 43/43/43 32/32/32 +f 32/32/32 43/43/43 31/31/31 +f 44/44/44 31/31/31 43/43/43 +f 31/31/31 44/44/44 29/29/29 +f 29/29/29 44/44/44 39/39/39 +f 39/39/39 44/44/44 26/26/26 +f 26/26/26 44/44/44 24/24/24 +f 45/45/45 24/24/24 44/44/44 +f 24/24/24 45/45/45 23/23/23 +f 23/23/23 45/45/45 46/46/46 +f 47/47/47 46/46/46 45/45/45 +f 46/46/46 47/47/47 48/48/48 +f 48/48/48 47/47/47 49/49/49 +f 50/50/50 49/49/49 47/47/47 +f 51/51/51 50/50/50 47/47/47 +f 50/50/50 51/51/51 42/42/42 +f 42/42/42 51/51/51 43/43/43 +f 52/52/52 43/43/43 51/51/51 +f 43/43/43 52/52/52 44/44/44 +f 44/44/44 52/52/52 45/45/45 +f 51/51/51 45/45/45 52/52/52 +f 45/45/45 51/51/51 47/47/47 +f 46/46/46 54/54/54 53/53/53 +f 48/48/48 54/54/54 46/46/46 +f 54/54/54 48/48/48 55/55/55 +f 55/55/55 48/48/48 56/56/56 +f 56/56/56 48/48/48 57/57/57 +f 57/57/57 48/48/48 58/58/58 +f 49/49/49 58/58/58 48/48/48 +f 58/58/58 49/49/49 59/59/59 +f 59/59/59 49/49/49 60/60/60 +f 60/60/60 49/49/49 61/61/61 +f 61/61/61 49/49/49 62/62/62 +f 62/62/62 49/49/49 63/63/63 +f 50/50/50 63/63/63 49/49/49 +f 63/63/63 50/50/50 64/64/64 +f 42/42/42 64/64/64 50/50/50 +f 64/64/64 42/42/42 40/40/40 +f 64/64/64 65/65/65 63/63/63 +f 65/65/65 64/64/64 66/66/66 +f 66/66/66 64/64/64 67/67/67 +f 67/67/67 64/64/64 68/68/68 +f 68/68/68 64/64/64 69/69/69 +f 40/40/40 69/69/69 64/64/64 +f 69/69/69 40/40/40 70/70/70 +f 70/70/70 40/40/40 56/56/56 +f 56/56/56 40/40/40 71/71/71 +f 71/71/71 40/40/40 72/72/72 +f 41/41/41 72/72/72 40/40/40 +f 72/72/72 41/41/41 53/53/53 +f 53/53/53 41/41/41 73/73/73 +f 74/74/74 73/73/73 41/41/41 +f 46/46/46 73/73/73 74/74/74 +f 73/73/73 46/46/46 53/53/53 +f 23/23/23 75/75/75 22/22/22 +f 75/75/75 23/23/23 76/76/76 +f 46/46/46 76/76/76 23/23/23 +f 76/76/76 46/46/46 77/77/77 +f 74/74/74 77/77/77 46/46/46 +f 41/41/41 77/77/77 74/74/74 +f 77/77/77 41/41/41 76/76/76 +f 32/32/32 76/76/76 41/41/41 +f 76/76/76 32/32/32 75/75/75 +f 22/22/22 75/75/75 32/32/32 +f 80/80/80 79/79/79 78/78/78 +f 79/79/79 80/80/80 81/81/81 +f 84/84/84 83/83/83 82/82/82 +f 83/83/83 84/84/84 78/78/78 +f 86/86/86 85/85/85 82/82/82 +f 85/85/85 86/86/86 87/87/87 +f 88/88/88 87/87/87 86/86/86 +f 87/87/87 88/88/88 89/89/89 +f 89/89/89 88/88/88 90/90/90 +f 91/91/91 90/90/90 88/88/88 +f 90/90/90 91/91/91 92/92/92 +f 81/81/81 92/92/92 91/91/91 +f 95/95/95 94/94/94 93/93/93 +f 94/94/94 95/95/95 96/96/96 +f 85/85/85 96/96/96 95/95/95 +f 96/96/96 85/85/85 97/97/97 +f 87/87/87 97/97/97 85/85/85 +f 97/97/97 87/87/87 98/98/98 +f 89/89/89 98/98/98 87/87/87 +f 98/98/98 89/89/89 99/99/99 +f 99/99/99 89/89/89 100/100/100 +f 90/90/90 100/100/100 89/89/89 +f 100/100/100 90/90/90 101/101/101 +f 92/92/92 101/101/101 90/90/90 +f 101/101/101 92/92/92 102/102/102 +f 103/103/103 102/102/102 92/92/92 +f 102/102/102 103/103/103 94/94/94 +f 93/93/93 94/94/94 103/103/103 +f 106/106/106 105/105/105 104/104/104 +f 107/107/107 105/105/105 106/106/106 +f 105/105/105 107/107/107 102/102/102 +f 102/102/102 107/107/107 101/101/101 +f 108/108/108 101/101/101 107/107/107 +f 101/101/101 108/108/108 100/100/100 +f 100/100/100 108/108/108 109/109/109 +f 109/109/109 108/108/108 98/98/98 +f 98/98/98 108/108/108 97/97/97 +f 110/110/110 97/97/97 108/108/108 +f 97/97/97 110/110/110 96/96/96 +f 96/96/96 110/110/110 111/111/111 +f 112/112/112 111/111/111 110/110/110 +f 111/111/111 112/112/112 113/113/113 +f 113/113/113 112/112/112 114/114/114 +f 115/115/115 114/114/114 112/112/112 +f 116/116/116 115/115/115 112/112/112 +f 115/115/115 116/116/116 106/106/106 +f 106/106/106 116/116/116 107/107/107 +f 117/117/117 107/107/107 116/116/116 +f 107/107/107 117/117/117 108/108/108 +f 108/108/108 117/117/117 110/110/110 +f 116/116/116 110/110/110 117/117/117 +f 110/110/110 116/116/116 112/112/112 +f 118/118/118 106/106/106 104/104/104 +f 106/106/106 118/118/118 115/115/115 +f 119/119/119 115/115/115 118/118/118 +f 115/115/115 119/119/119 114/114/114 +f 120/120/120 114/114/114 119/119/119 +f 121/121/121 114/114/114 120/120/120 +f 122/122/122 114/114/114 121/121/121 +f 123/123/123 114/114/114 122/122/122 +f 124/124/124 114/114/114 123/123/123 +f 114/114/114 124/124/124 113/113/113 +f 125/125/125 113/113/113 124/124/124 +f 126/126/126 113/113/113 125/125/125 +f 127/127/127 113/113/113 126/126/126 +f 128/128/128 113/113/113 127/127/127 +f 113/113/113 128/128/128 111/111/111 +f 111/111/111 128/128/128 129/129/129 +f 118/118/118 130/130/130 119/119/119 +f 130/130/130 118/118/118 131/131/131 +f 131/131/131 118/118/118 132/132/132 +f 132/132/132 118/118/118 133/133/133 +f 133/133/133 118/118/118 134/134/134 +f 104/104/104 134/134/134 118/118/118 +f 134/134/134 104/104/104 135/135/135 +f 135/135/135 104/104/104 126/126/126 +f 126/126/126 104/104/104 136/136/136 +f 136/136/136 104/104/104 137/137/137 +f 105/105/105 137/137/137 104/104/104 +f 137/137/137 105/105/105 129/129/129 +f 129/129/129 105/105/105 138/138/138 +f 139/139/139 138/138/138 105/105/105 +f 111/111/111 138/138/138 139/139/139 +f 138/138/138 111/111/111 129/129/129 +f 96/96/96 140/140/140 94/94/94 +f 140/140/140 96/96/96 141/141/141 +f 111/111/111 141/141/141 96/96/96 +f 141/141/141 111/111/111 142/142/142 +f 139/139/139 142/142/142 111/111/111 +f 105/105/105 142/142/142 139/139/139 +f 142/142/142 105/105/105 141/141/141 +f 102/102/102 141/141/141 105/105/105 +f 141/141/141 102/102/102 140/140/140 +f 94/94/94 140/140/140 102/102/102 +f 144/144/144 143/143/143 8/8/8 +f 143/143/143 144/144/144 36/36/36 +f 147/147/147 146/146/146 145/145/145 +f 146/146/146 147/147/147 148/148/148 +f 149/149/149 150/150/150 145/145/145 +f 151/151/151 145/145/145 150/150/150 +f 145/145/145 151/151/151 147/147/147 +f 152/152/152 147/147/147 151/151/151 +f 153/153/153 147/147/147 152/152/152 +f 147/147/147 153/153/153 148/148/148 +f 150/150/150 148/148/148 153/153/153 +f 148/148/148 150/150/150 154/154/154 +f 155/155/155 154/154/154 150/150/150 +f 154/154/154 155/155/155 156/156/156 +f 157/157/157 156/156/156 155/155/155 +f 156/156/156 157/157/157 158/158/158 +f 159/159/159 158/158/158 157/157/157 +f 158/158/158 159/159/159 160/160/160 +f 161/161/161 160/160/160 159/159/159 +f 160/160/160 161/161/161 162/162/162 +f 149/149/149 155/155/155 150/150/150 +f 163/163/163 155/155/155 149/149/149 +f 155/155/155 163/163/163 157/157/157 +f 164/164/164 157/157/157 163/163/163 +f 157/157/157 164/164/164 159/159/159 +f 165/165/165 159/159/159 164/164/164 +f 159/159/159 165/165/165 161/161/161 +f 161/161/161 165/165/165 166/166/166 +f 166/166/166 165/165/165 167/167/167 +f 168/168/168 167/167/167 165/165/165 +f 160/160/160 167/167/167 168/168/168 +f 167/167/167 160/160/160 162/162/162 +f 156/156/156 170/170/170 169/169/169 +f 170/170/170 156/156/156 171/171/171 +f 158/158/158 171/171/171 156/156/156 +f 160/160/160 171/171/171 158/158/158 +f 171/171/171 160/160/160 172/172/172 +f 168/168/168 172/172/172 160/160/160 +f 172/172/172 168/168/168 173/173/173 +f 173/173/173 168/168/168 174/174/174 +f 165/165/165 174/174/174 168/168/168 +f 174/174/174 165/165/165 171/171/171 +f 164/164/164 171/171/171 165/165/165 +f 163/163/163 171/171/171 164/164/164 +f 171/171/171 163/163/163 170/170/170 +f 170/170/170 163/163/163 169/169/169 +f 149/149/149 169/169/169 163/163/163 +f 169/169/169 149/149/149 175/175/175 +f 172/172/172 176/176/176 171/171/171 +f 176/176/176 172/172/172 177/177/177 +f 173/173/173 177/177/177 172/172/172 +f 174/174/174 177/177/177 173/173/173 +f 177/177/177 174/174/174 176/176/176 +f 171/171/171 176/176/176 174/174/174 +f 169/169/169 154/154/154 156/156/156 +f 154/154/154 169/169/169 175/175/175 +f 154/154/154 178/178/178 148/148/148 +f 178/178/178 154/154/154 179/179/179 +f 175/175/175 179/179/179 154/154/154 +f 149/149/149 179/179/179 175/175/175 +f 179/179/179 149/149/149 178/178/178 +f 145/145/145 178/178/178 149/149/149 +f 182/182/182 181/181/181 180/180/180 +f 181/181/181 182/182/182 183/183/183 +f 184/184/184 181/181/181 183/183/183 +f 181/181/181 184/184/184 185/185/185 +f 186/186/186 185/185/185 184/184/184 +f 187/187/187 185/185/185 186/186/186 +f 185/185/185 187/187/187 188/188/188 +f 189/189/189 188/188/188 187/187/187 +f 188/188/188 189/189/189 190/190/190 +f 191/191/191 190/190/190 189/189/189 +f 190/190/190 191/191/191 192/192/192 +f 192/192/192 191/191/191 193/193/193 +f 189/189/189 193/193/193 191/191/191 +f 193/193/193 189/189/189 194/194/194 +f 195/195/195 194/194/194 189/189/189 +f 194/194/194 195/195/195 180/180/180 +f 186/186/186 180/180/180 195/195/195 +f 180/180/180 186/186/186 182/182/182 +f 181/181/181 185/185/185 196/196/196 +f 188/188/188 196/196/196 185/185/185 +f 196/196/196 188/188/188 197/197/197 +f 190/190/190 197/197/197 188/188/188 +f 197/197/197 190/190/190 198/198/198 +f 192/192/192 198/198/198 190/190/190 +f 199/199/199 198/198/198 192/192/192 +f 198/198/198 199/199/199 200/200/200 +f 201/201/201 200/200/200 199/199/199 +f 200/200/200 201/201/201 202/202/202 +f 203/203/203 202/202/202 201/201/201 +f 202/202/202 203/203/203 204/204/204 +f 196/196/196 180/180/180 181/181/181 +f 180/180/180 196/196/196 194/194/194 +f 197/197/197 194/194/194 196/196/196 +f 194/194/194 197/197/197 193/193/193 +f 205/205/205 193/193/193 197/197/197 +f 193/193/193 205/205/205 192/192/192 +f 192/192/192 205/205/205 199/199/199 +f 206/206/206 199/199/199 205/205/205 +f 199/199/199 206/206/206 207/207/207 +f 208/208/208 207/207/207 206/206/206 +f 207/207/207 208/208/208 209/209/209 +f 210/210/210 209/209/209 208/208/208 +f 211/211/211 209/209/209 210/210/210 +f 209/209/209 211/211/211 212/212/212 +f 212/212/212 211/211/211 203/203/203 +f 204/204/204 203/203/203 211/211/211 +f 214/214/214 204/204/204 213/213/213 +f 204/204/204 214/214/214 202/202/202 +f 215/215/215 202/202/202 214/214/214 +f 202/202/202 215/215/215 200/200/200 +f 216/216/216 200/200/200 215/215/215 +f 200/200/200 216/216/216 198/198/198 +f 198/198/198 216/216/216 197/197/197 +f 197/197/197 216/216/216 205/205/205 +f 205/205/205 216/216/216 206/206/206 +f 215/215/215 206/206/206 216/216/216 +f 206/206/206 215/215/215 208/208/208 +f 214/214/214 208/208/208 215/215/215 +f 208/208/208 214/214/214 210/210/210 +f 213/213/213 210/210/210 214/214/214 +f 219/219/219 218/218/218 217/217/217 +f 218/218/218 219/219/219 220/220/220 +f 220/220/220 219/219/219 221/221/221 +f 222/222/222 221/221/221 219/219/219 +f 225/225/225 224/224/224 223/223/223 +f 224/224/224 225/225/225 226/226/226 +f 225/225/225 227/227/227 226/226/226 +f 227/227/227 225/225/225 228/228/228 +f 229/229/229 228/228/228 225/225/225 +f 228/228/228 229/229/229 230/230/230 +f 231/231/231 230/230/230 229/229/229 +f 232/232/232 230/230/230 231/231/231 +f 230/230/230 232/232/232 233/233/233 +f 234/234/234 233/233/233 232/232/232 +f 233/233/233 234/234/234 235/235/235 +f 235/235/235 234/234/234 236/236/236 +f 232/232/232 236/236/236 234/234/234 +f 236/236/236 232/232/232 237/237/237 +f 231/231/231 237/237/237 232/232/232 +f 229/229/229 237/237/237 231/231/231 +f 237/237/237 229/229/229 223/223/223 +f 225/225/225 223/223/223 229/229/229 +f 224/224/224 238/238/238 223/223/223 +f 239/239/239 223/223/223 238/238/238 +f 223/223/223 239/239/239 237/237/237 +f 240/240/240 237/237/237 239/239/239 +f 237/237/237 240/240/240 236/236/236 +f 241/241/241 236/236/236 240/240/240 +f 236/236/236 241/241/241 235/235/235 +f 235/235/235 241/241/241 233/233/233 +f 240/240/240 233/233/233 241/241/241 +f 233/233/233 240/240/240 230/230/230 +f 239/239/239 230/230/230 240/240/240 +f 230/230/230 239/239/239 228/228/228 +f 238/238/238 228/228/228 239/239/239 +f 228/228/228 238/238/238 227/227/227 +f 242/242/242 227/227/227 238/238/238 +f 227/227/227 242/242/242 243/243/243 +f 224/224/224 242/242/242 238/238/238 +f 242/242/242 224/224/224 244/244/244 +f 244/244/244 224/224/224 245/245/245 +f 226/226/226 245/245/245 224/224/224 +f 227/227/227 245/245/245 226/226/226 +f 245/245/245 227/227/227 243/243/243 +f 248/248/248 247/247/247 246/246/246 +f 249/249/249 247/247/247 248/248/248 +f 247/247/247 249/249/249 250/250/250 +f 251/251/251 250/250/250 249/249/249 +f 250/250/250 251/251/251 252/252/252 +f 253/253/253 252/252/252 251/251/251 +f 252/252/252 253/253/253 244/244/244 +f 254/254/254 244/244/244 253/253/253 +f 244/244/244 254/254/254 242/242/242 +f 242/242/242 254/254/254 243/243/243 +f 253/253/253 243/243/243 254/254/254 +f 243/243/243 253/253/253 255/255/255 +f 251/251/251 255/255/255 253/253/253 +f 255/255/255 251/251/251 256/256/256 +f 256/256/256 251/251/251 257/257/257 +f 258/258/258 257/257/257 251/251/251 +f 248/248/248 246/246/246 259/259/259 +f 260/260/260 259/259/259 246/246/246 +f 259/259/259 260/260/260 261/261/261 +f 261/261/261 260/260/260 262/262/262 +f 246/246/246 262/262/262 260/260/260 +f 262/262/262 246/246/246 263/263/263 +f 264/264/264 263/263/263 246/246/246 +f 263/263/263 264/264/264 257/257/257 +f 257/257/257 264/264/264 256/256/256 +f 265/265/265 256/256/256 264/264/264 +f 266/266/266 256/256/256 265/265/265 +f 256/256/256 266/266/266 255/255/255 +f 267/267/267 255/255/255 266/266/266 +f 255/255/255 267/267/267 243/243/243 +f 268/268/268 243/243/243 267/267/267 +f 243/243/243 268/268/268 245/245/245 +f 250/250/250 265/265/265 247/247/247 +f 265/265/265 250/250/250 266/266/266 +f 252/252/252 266/266/266 250/250/250 +f 266/266/266 252/252/252 267/267/267 +f 244/244/244 267/267/267 252/252/252 +f 267/267/267 244/244/244 269/269/269 +f 245/245/245 269/269/269 244/244/244 +f 269/269/269 245/245/245 270/270/270 +f 268/268/268 270/270/270 245/245/245 +f 271/271/271 270/270/270 268/268/268 +f 270/270/270 271/271/271 269/269/269 +f 272/272/272 269/269/269 271/271/271 +f 269/269/269 272/272/272 267/267/267 +f 267/267/267 272/272/272 268/268/268 +f 271/271/271 268/268/268 272/272/272 +f 275/275/275 274/274/274 273/273/273 +f 274/274/274 275/275/275 276/276/276 +f 279/279/279 278/278/278 277/277/277 +f 278/278/278 279/279/279 280/280/280 +f 281/281/281 280/280/280 279/279/279 +f 282/282/282 280/280/280 281/281/281 +f 280/280/280 282/282/282 283/283/283 +f 276/276/276 283/283/283 282/282/282 +f 275/275/275 283/283/283 276/276/276 +f 283/283/283 275/275/275 280/280/280 +f 280/280/280 275/275/275 278/278/278 +f 273/273/273 278/278/278 275/275/275 +f 278/278/278 273/273/273 284/284/284 +f 285/285/285 284/284/284 273/273/273 +f 284/284/284 285/285/285 286/286/286 +f 286/286/286 285/285/285 287/287/287 +f 273/273/273 287/287/287 285/285/285 +f 287/287/287 273/273/273 274/274/274 +f 278/278/278 288/288/288 277/277/277 +f 274/274/274 277/277/277 288/288/288 +f 277/277/277 274/274/274 279/279/279 +f 276/276/276 279/279/279 274/274/274 +f 279/279/279 276/276/276 289/289/289 +f 282/282/282 289/289/289 276/276/276 +f 289/289/289 282/282/282 290/290/290 +f 281/281/281 290/290/290 282/282/282 +f 291/291/291 290/290/290 281/281/281 +f 290/290/290 291/291/291 289/289/289 +f 292/292/292 289/289/289 291/291/291 +f 293/293/293 289/289/289 292/292/292 +f 289/289/289 293/293/293 294/294/294 +f 294/294/294 293/293/293 281/281/281 +f 295/295/295 281/281/281 293/293/293 +f 281/281/281 295/295/295 291/291/291 +f 296/296/296 274/274/274 288/288/288 +f 274/274/274 296/296/296 287/287/287 +f 297/297/297 287/287/287 296/296/296 +f 287/287/287 297/297/297 286/286/286 +f 286/286/286 297/297/297 284/284/284 +f 296/296/296 284/284/284 297/297/297 +f 284/284/284 296/296/296 278/278/278 +f 288/288/288 278/278/278 296/296/296 +f 300/300/300 299/299/299 298/298/298 +f 299/299/299 300/300/300 292/292/292 +f 301/301/301 292/292/292 300/300/300 +f 292/292/292 301/301/301 293/293/293 +f 293/293/293 301/301/301 295/295/295 +f 300/300/300 295/295/295 301/301/301 +f 295/295/295 300/300/300 258/258/258 +f 298/298/298 258/258/258 300/300/300 +f 292/292/292 291/291/291 302/302/302 +f 295/295/295 302/302/302 291/291/291 +f 302/302/302 295/295/295 303/303/303 +f 258/258/258 303/303/303 295/295/295 +f 303/303/303 258/258/258 304/304/304 +f 251/251/251 304/304/304 258/258/258 +f 305/305/305 304/304/304 251/251/251 +f 304/304/304 305/305/305 306/306/306 +f 306/306/306 305/305/305 307/307/307 +f 251/251/251 307/307/307 305/305/305 +f 307/307/307 251/251/251 299/299/299 +f 249/249/249 299/299/299 251/251/251 +f 308/308/308 299/299/299 249/249/249 +f 299/299/299 308/308/308 298/298/298 +f 298/298/298 308/308/308 258/258/258 +f 258/258/258 308/308/308 257/257/257 +f 303/303/303 292/292/292 302/302/302 +f 292/292/292 303/303/303 299/299/299 +f 299/299/299 303/303/303 307/307/307 +f 307/307/307 303/303/303 309/309/309 +f 304/304/304 309/309/309 303/303/303 +f 309/309/309 304/304/304 310/310/310 +f 306/306/306 310/310/310 304/304/304 +f 307/307/307 310/310/310 306/306/306 +f 310/310/310 307/307/307 309/309/309 +f 312/312/312 259/259/259 311/311/311 +f 313/313/313 259/259/259 312/312/312 +f 259/259/259 313/313/313 248/248/248 +f 314/314/314 248/248/248 313/313/313 +f 315/315/315 248/248/248 314/314/314 +f 248/248/248 315/315/315 249/249/249 +f 316/316/316 249/249/249 315/315/315 +f 249/249/249 316/316/316 308/308/308 +f 308/308/308 316/316/316 257/257/257 +f 315/315/315 257/257/257 316/316/316 +f 257/257/257 315/315/315 263/263/263 +f 314/314/314 263/263/263 315/315/315 +f 317/317/317 263/263/263 314/314/314 +f 263/263/263 317/317/317 262/262/262 +f 312/312/312 262/262/262 317/317/317 +f 262/262/262 312/312/312 318/318/318 +f 259/259/259 261/261/261 311/311/311 +f 319/319/319 311/311/311 261/261/261 +f 311/311/311 319/319/319 320/320/320 +f 321/321/321 320/320/320 319/319/319 +f 320/320/320 321/321/321 322/322/322 +f 323/323/323 322/322/322 321/321/321 +f 322/322/322 323/323/323 324/324/324 +f 325/325/325 324/324/324 323/323/323 +f 326/326/326 324/324/324 325/325/325 +f 324/324/324 326/326/326 322/322/322 +f 327/327/327 322/322/322 326/326/326 +f 322/322/322 327/327/327 320/320/320 +f 328/328/328 320/320/320 327/327/327 +f 320/320/320 328/328/328 318/318/318 +f 261/261/261 318/318/318 328/328/328 +f 318/318/318 261/261/261 262/262/262 +f 329/329/329 328/328/328 327/327/327 +f 328/328/328 329/329/329 330/330/330 +f 330/330/330 329/329/329 319/319/319 +f 319/319/319 329/329/329 321/321/321 +f 321/321/321 329/329/329 323/323/323 +f 323/323/323 329/329/329 331/331/331 +f 331/331/331 329/329/329 326/326/326 +f 327/327/327 326/326/326 329/329/329 +f 332/332/332 319/319/319 261/261/261 +f 319/319/319 332/332/332 330/330/330 +f 330/330/330 332/332/332 328/328/328 +f 261/261/261 328/328/328 332/332/332 +f 333/333/333 326/326/326 325/325/325 +f 326/326/326 333/333/333 331/331/331 +f 334/334/334 331/331/331 333/333/333 +f 335/335/335 331/331/331 334/334/334 +f 331/331/331 335/335/335 323/323/323 +f 323/323/323 335/335/335 325/325/325 +f 336/336/336 325/325/325 335/335/335 +f 325/325/325 336/336/336 333/333/333 +f 337/337/337 333/333/333 336/336/336 +f 333/333/333 337/337/337 334/334/334 +f 338/338/338 334/334/334 337/337/337 +f 339/339/339 334/334/334 338/338/338 +f 334/334/334 339/339/339 335/335/335 +f 335/335/335 339/339/339 336/336/336 +f 340/340/340 336/336/336 339/339/339 +f 336/336/336 340/340/340 337/337/337 +f 341/341/341 337/337/337 340/340/340 +f 337/337/337 341/341/341 338/338/338 +f 338/338/338 341/341/341 339/339/339 +f 340/340/340 339/339/339 341/341/341 +f 344/344/344 343/343/343 342/342/342 +f 343/343/343 344/344/344 345/345/345 +f 342/342/342 347/347/347 346/346/346 +f 347/347/347 342/342/342 348/348/348 +f 343/343/343 348/348/348 342/342/342 +f 348/348/348 343/343/343 349/349/349 +f 345/345/345 349/349/349 343/343/343 +f 350/350/350 349/349/349 345/345/345 +f 349/349/349 350/350/350 351/351/351 +f 352/352/352 351/351/351 350/350/350 +f 351/351/351 352/352/352 353/353/353 +f 353/353/353 352/352/352 354/354/354 +f 354/354/354 352/352/352 355/355/355 +f 356/356/356 355/355/355 352/352/352 +f 355/355/355 356/356/356 357/357/357 +f 357/357/357 356/356/356 358/358/358 +f 359/359/359 358/358/358 356/356/356 +f 358/358/358 359/359/359 360/360/360 +f 344/344/344 350/350/350 345/345/345 +f 350/350/350 344/344/344 352/352/352 +f 361/361/361 352/352/352 344/344/344 +f 352/352/352 361/361/361 356/356/356 +f 362/362/362 356/356/356 361/361/361 +f 363/363/363 356/356/356 362/362/362 +f 356/356/356 363/363/363 359/359/359 +f 364/364/364 359/359/359 363/363/363 +f 359/359/359 364/364/364 365/365/365 +f 365/365/365 364/364/364 366/366/366 +f 363/363/363 366/366/366 364/364/364 +f 366/366/366 363/363/363 367/367/367 +f 362/362/362 367/367/367 363/363/363 +f 361/361/361 367/367/367 362/362/362 +f 367/367/367 361/361/361 342/342/342 +f 344/344/344 342/342/342 361/361/361 +f 359/359/359 368/368/368 360/360/360 +f 365/365/365 368/368/368 359/359/359 +f 366/366/366 368/368/368 365/365/365 +f 368/368/368 366/366/366 369/369/369 +f 369/369/369 366/366/366 370/370/370 +f 367/367/367 370/370/370 366/366/366 +f 370/370/370 367/367/367 371/371/371 +f 371/371/371 367/367/367 372/372/372 +f 342/342/342 372/372/372 367/367/367 +f 372/372/372 342/342/342 346/346/346 +f 375/375/375 374/374/374 373/373/373 +f 374/374/374 375/375/375 376/376/376 +f 379/379/379 378/378/378 377/377/377 +f 378/378/378 379/379/379 380/380/380 +f 381/381/381 380/380/380 379/379/379 +f 380/380/380 381/381/381 376/376/376 +f 376/376/376 381/381/381 374/374/374 +f 382/382/382 374/374/374 381/381/381 +f 374/374/374 382/382/382 373/373/373 +f 383/383/383 373/373/373 382/382/382 +f 384/384/384 373/373/373 383/383/383 +f 385/385/385 373/373/373 384/384/384 +f 373/373/373 385/385/385 386/386/386 +f 387/387/387 386/386/386 385/385/385 +f 388/388/388 386/386/386 387/387/387 +f 386/386/386 388/388/388 389/389/389 +f 390/390/390 389/389/389 388/388/388 +f 389/389/389 390/390/390 391/391/391 +f 375/375/375 380/380/380 376/376/376 +f 380/380/380 375/375/375 378/378/378 +f 392/392/392 378/378/378 375/375/375 +f 378/378/378 392/392/392 393/393/393 +f 394/394/394 393/393/393 392/392/392 +f 395/395/395 393/393/393 394/394/394 +f 393/393/393 395/395/395 396/396/396 +f 397/397/397 396/396/396 395/395/395 +f 396/396/396 397/397/397 398/398/398 +f 398/398/398 397/397/397 389/389/389 +f 395/395/395 389/389/389 397/397/397 +f 389/389/389 395/395/395 386/386/386 +f 394/394/394 386/386/386 395/395/395 +f 392/392/392 386/386/386 394/394/394 +f 386/386/386 392/392/392 373/373/373 +f 375/375/375 373/373/373 392/392/392 +f 391/391/391 398/398/398 389/389/389 +f 398/398/398 391/391/391 396/396/396 +f 399/399/399 396/396/396 391/391/391 +f 400/400/400 396/396/396 399/399/399 +f 396/396/396 400/400/400 393/393/393 +f 401/401/401 393/393/393 400/400/400 +f 402/402/402 393/393/393 401/401/401 +f 393/393/393 402/402/402 378/378/378 +f 403/403/403 378/378/378 402/402/402 +f 378/378/378 403/403/403 377/377/377 +f 406/406/406 405/405/405 404/404/404 +f 405/405/405 406/406/406 407/407/407 +f 407/407/407 406/406/406 408/408/408 +f 409/409/409 408/408/408 406/406/406 +f 411/411/411 410/410/410 152/152/152 +f 410/410/410 411/411/411 412/412/412 +f 412/412/412 411/411/411 413/413/413 +f 152/152/152 413/413/413 411/411/411 +f 414/414/414 410/410/410 412/412/412 +f 410/410/410 414/414/414 150/150/150 +f 150/150/150 414/414/414 413/413/413 +f 412/412/412 413/413/413 414/414/414 +f 417/417/417 416/416/416 415/415/415 +f 416/416/416 417/417/417 418/418/418 +f 419/419/419 418/418/418 417/417/417 +f 418/418/418 419/419/419 420/420/420 +f 421/421/421 420/420/420 419/419/419 +f 420/420/420 421/421/421 422/422/422 +f 425/425/425 424/424/424 423/423/423 +f 426/426/426 424/424/424 425/425/425 +f 424/424/424 426/426/426 427/427/427 +f 428/428/428 427/427/427 426/426/426 +f 427/427/427 428/428/428 429/429/429 +f 430/430/430 429/429/429 428/428/428 +f 433/433/433 432/432/432 431/431/431 +f 432/432/432 433/433/433 434/434/434 +f 435/435/435 434/434/434 433/433/433 +f 434/434/434 435/435/435 436/436/436 +f 437/437/437 436/436/436 435/435/435 +f 436/436/436 437/437/437 438/438/438 +f 441/441/441 440/440/440 439/439/439 +f 442/442/442 440/440/440 441/441/441 +f 440/440/440 442/442/442 443/443/443 +f 444/444/444 443/443/443 442/442/442 +f 443/443/443 444/444/444 445/445/445 +f 446/446/446 445/445/445 444/444/444 +f 449/449/449 448/448/448 447/447/447 +f 448/448/448 449/449/449 450/450/450 +f 450/450/450 449/449/449 451/451/451 +f 447/447/447 451/451/451 449/449/449 +f 453/453/453 448/448/448 452/452/452 +f 448/448/448 453/453/453 447/447/447 +f 454/454/454 447/447/447 453/453/453 +f 447/447/447 454/454/454 455/455/455 +f 456/456/456 455/455/455 454/454/454 +f 457/457/457 455/455/455 456/456/456 +f 455/455/455 457/457/457 447/447/447 +f 458/458/458 447/447/447 457/457/457 +f 447/447/447 458/458/458 451/451/451 +f 452/452/452 451/451/451 458/458/458 +f 451/451/451 452/452/452 459/459/459 +f 448/448/448 459/459/459 452/452/452 +f 459/459/459 448/448/448 460/460/460 +f 450/450/450 460/460/460 448/448/448 +f 460/460/460 450/450/450 461/461/461 +f 462/462/462 461/461/461 450/450/450 +f 451/451/451 462/462/462 450/450/450 +f 459/459/459 462/462/462 451/451/451 +f 462/462/462 459/459/459 463/463/463 +f 460/460/460 463/463/463 459/459/459 +f 461/461/461 463/463/463 460/460/460 +f 463/463/463 461/461/461 462/462/462 +f 466/466/466 465/465/465 464/464/464 +f 465/465/465 466/466/466 453/453/453 +f 467/467/467 453/453/453 466/466/466 +f 453/453/453 467/467/467 454/454/454 +f 454/454/454 467/467/467 468/468/468 +f 469/469/469 468/468/468 467/467/467 +f 470/470/470 468/468/468 469/469/469 +f 468/468/468 470/470/470 457/457/457 +f 457/457/457 470/470/470 458/458/458 +f 466/466/466 458/458/458 470/470/470 +f 458/458/458 466/466/466 471/471/471 +f 464/464/464 471/471/471 466/466/466 +f 472/472/472 457/457/457 456/456/456 +f 457/457/457 472/472/472 468/468/468 +f 468/468/468 472/472/472 454/454/454 +f 456/456/456 454/454/454 472/472/472 +f 473/473/473 467/467/467 466/466/466 +f 467/467/467 473/473/473 474/474/474 +f 474/474/474 473/473/473 470/470/470 +f 466/466/466 470/470/470 473/473/473 +f 475/475/475 469/469/469 467/467/467 +f 469/469/469 475/475/475 470/470/470 +f 470/470/470 475/475/475 474/474/474 +f 467/467/467 474/474/474 475/475/475 +f 478/478/478 477/477/477 476/476/476 +f 477/477/477 478/478/478 465/465/465 +f 479/479/479 465/465/465 478/478/478 +f 465/465/465 479/479/479 464/464/464 +f 464/464/464 479/479/479 471/471/471 +f 478/478/478 471/471/471 479/479/479 +f 471/471/471 478/478/478 480/480/480 +f 476/476/476 480/480/480 478/478/478 +f 281/281/281 481/481/481 294/294/294 +f 481/481/481 281/281/281 477/477/477 +f 279/279/279 477/477/477 281/281/281 +f 477/477/477 279/279/279 476/476/476 +f 476/476/476 279/279/279 480/480/480 +f 289/289/289 480/480/480 279/279/279 +f 480/480/480 289/289/289 481/481/481 +f 294/294/294 481/481/481 289/289/289 +f 482/482/482 480/480/480 481/481/481 +f 480/480/480 482/482/482 483/483/483 +f 484/484/484 483/483/483 482/482/482 +f 483/483/483 484/484/484 485/485/485 +f 485/485/485 484/484/484 486/486/486 +f 482/482/482 486/486/486 484/484/484 +f 486/486/486 482/482/482 477/477/477 +f 481/481/481 477/477/477 482/482/482 +f 487/487/487 483/483/483 485/485/485 +f 483/483/483 487/487/487 480/480/480 +f 480/480/480 487/487/487 471/471/471 +f 488/488/488 471/471/471 487/487/487 +f 471/471/471 488/488/488 458/458/458 +f 489/489/489 458/458/458 488/488/488 +f 458/458/458 489/489/489 452/452/452 +f 452/452/452 489/489/489 453/453/453 +f 488/488/488 453/453/453 489/489/489 +f 453/453/453 488/488/488 465/465/465 +f 487/487/487 465/465/465 488/488/488 +f 465/465/465 487/487/487 477/477/477 +f 477/477/477 487/487/487 486/486/486 +f 485/485/485 486/486/486 487/487/487 +f 490/490/490 318/318/318 312/312/312 +f 318/318/318 490/490/490 320/320/320 +f 320/320/320 490/490/490 311/311/311 +f 312/312/312 311/311/311 490/490/490 +f 492/492/492 317/317/317 491/491/491 +f 317/317/317 492/492/492 312/312/312 +f 312/312/312 492/492/492 313/313/313 +f 491/491/491 313/313/313 492/492/492 +f 493/493/493 317/317/317 314/314/314 +f 317/317/317 493/493/493 491/491/491 +f 491/491/491 493/493/493 313/313/313 +f 314/314/314 313/313/313 493/493/493 +f 496/496/496 495/495/495 494/494/494 +f 495/495/495 496/496/496 497/497/497 +f 497/497/497 496/496/496 498/498/498 +f 494/494/494 498/498/498 496/496/496 +f 501/501/501 500/500/500 499/499/499 +f 500/500/500 501/501/501 502/502/502 +f 503/503/503 502/502/502 501/501/501 +f 502/502/502 503/503/503 498/498/498 +f 504/504/504 498/498/498 503/503/503 +f 498/498/498 504/504/504 497/497/497 +f 497/497/497 504/504/504 495/495/495 +f 503/503/503 495/495/495 504/504/504 +f 495/495/495 503/503/503 505/505/505 +f 506/506/506 505/505/505 503/503/503 +f 505/505/505 506/506/506 507/507/507 +f 507/507/507 506/506/506 499/499/499 +f 508/508/508 499/499/499 506/506/506 +f 499/499/499 508/508/508 501/501/501 +f 501/501/501 508/508/508 509/509/509 +f 506/506/506 509/509/509 508/508/508 +f 506/506/506 510/510/510 509/509/509 +f 503/503/503 510/510/510 506/506/506 +f 501/501/501 510/510/510 503/503/503 +f 510/510/510 501/501/501 509/509/509 +f 513/513/513 512/512/512 511/511/511 +f 500/500/500 512/512/512 513/513/513 +f 502/502/502 512/512/512 500/500/500 +f 512/512/512 502/502/502 514/514/514 +f 515/515/515 514/514/514 502/502/502 +f 514/514/514 515/515/515 505/505/505 +f 505/505/505 515/515/515 495/495/495 +f 516/516/516 495/495/495 515/515/515 +f 495/495/495 516/516/516 517/517/517 +f 518/518/518 517/517/517 516/516/516 +f 517/517/517 518/518/518 519/519/519 +f 520/520/520 519/519/519 518/518/518 +f 519/519/519 520/520/520 521/521/521 +f 521/521/521 520/520/520 522/522/522 +f 518/518/518 522/522/522 520/520/520 +f 522/522/522 518/518/518 523/523/523 +f 519/519/519 524/524/524 517/517/517 +f 525/525/525 517/517/517 524/524/524 +f 517/517/517 525/525/525 495/495/495 +f 526/526/526 495/495/495 525/525/525 +f 495/495/495 526/526/526 494/494/494 +f 162/162/162 494/494/494 526/526/526 +f 494/494/494 162/162/162 527/527/527 +f 161/161/161 527/527/527 162/162/162 +f 166/166/166 527/527/527 161/161/161 +f 527/527/527 166/166/166 494/494/494 +f 528/528/528 494/494/494 166/166/166 +f 494/494/494 528/528/528 498/498/498 +f 525/525/525 498/498/498 528/528/528 +f 498/498/498 525/525/525 523/523/523 +f 524/524/524 523/523/523 525/525/525 +f 523/523/523 524/524/524 522/522/522 +f 529/529/529 526/526/526 525/525/525 +f 526/526/526 529/529/529 162/162/162 +f 530/530/530 162/162/162 529/529/529 +f 162/162/162 530/530/530 167/167/167 +f 167/167/167 530/530/530 166/166/166 +f 529/529/529 166/166/166 530/530/530 +f 166/166/166 529/529/529 528/528/528 +f 525/525/525 528/528/528 529/529/529 +f 516/516/516 523/523/523 518/518/518 +f 523/523/523 516/516/516 498/498/498 +f 515/515/515 498/498/498 516/516/516 +f 498/498/498 515/515/515 502/502/502 +f 533/533/533 532/532/532 531/531/531 +f 532/532/532 533/533/533 534/534/534 +f 534/534/534 533/533/533 535/535/535 +f 531/531/531 535/535/535 533/533/533 +f 536/536/536 532/532/532 534/534/534 +f 532/532/532 536/536/536 537/537/537 +f 537/537/537 536/536/536 535/535/535 +f 534/534/534 535/535/535 536/536/536 +f 540/540/540 539/539/539 538/538/538 +f 539/539/539 540/540/540 541/541/541 +f 541/541/541 540/540/540 542/542/542 +f 543/543/543 542/542/542 540/540/540 +f 542/542/542 543/543/543 531/531/531 +f 531/531/531 543/543/543 535/535/535 +f 540/540/540 535/535/535 543/543/543 +f 544/544/544 535/535/535 540/540/540 +f 545/545/545 535/535/535 544/544/544 +f 535/535/535 545/545/545 537/537/537 +f 546/546/546 537/537/537 545/545/545 +f 547/547/547 537/537/537 546/546/546 +f 537/537/537 547/547/547 532/532/532 +f 548/548/548 532/532/532 547/547/547 +f 532/532/532 548/548/548 549/549/549 +f 550/550/550 549/549/549 548/548/548 +f 550/550/550 551/551/551 549/549/549 +f 552/552/552 549/549/549 551/551/551 +f 549/549/549 552/552/552 538/538/538 +f 538/538/538 552/552/552 540/540/540 +f 553/553/553 540/540/540 552/552/552 +f 554/554/554 540/540/540 553/553/553 +f 540/540/540 554/554/554 544/544/544 +f 555/555/555 544/544/544 554/554/554 +f 544/544/544 555/555/555 556/556/556 +f 556/556/556 555/555/555 548/548/548 +f 548/548/548 555/555/555 550/550/550 +f 544/544/544 557/557/557 545/545/545 +f 557/557/557 544/544/544 558/558/558 +f 559/559/559 558/558/558 544/544/544 +f 548/548/548 558/558/558 559/559/559 +f 558/558/558 548/548/548 557/557/557 +f 547/547/547 557/557/557 548/548/548 +f 557/557/557 547/547/547 560/560/560 +f 561/561/561 560/560/560 547/547/547 +f 559/559/559 562/562/562 548/548/548 +f 563/563/563 548/548/548 562/562/562 +f 548/548/548 563/563/563 556/556/556 +f 556/556/556 563/563/563 544/544/544 +f 562/562/562 544/544/544 563/563/563 +f 544/544/544 562/562/562 559/559/559 +f 560/560/560 545/545/545 557/557/557 +f 545/545/545 560/560/560 564/564/564 +f 564/564/564 560/560/560 565/565/565 +f 561/561/561 565/565/565 560/560/560 +f 566/566/566 565/565/565 561/561/561 +f 565/565/565 566/566/566 564/564/564 +f 567/567/567 564/564/564 566/566/566 +f 568/568/568 564/564/564 567/567/567 +f 564/564/564 568/568/568 545/545/545 +f 569/569/569 545/545/545 568/568/568 +f 545/545/545 569/569/569 546/546/546 +f 546/546/546 569/569/569 547/547/547 +f 568/568/568 547/547/547 569/569/569 +f 547/547/547 568/568/568 561/561/561 +f 570/570/570 561/561/561 568/568/568 +f 561/561/561 570/570/570 566/566/566 +f 573/573/573 572/572/572 571/571/571 +f 572/572/572 573/573/573 574/574/574 +f 574/574/574 573/573/573 575/575/575 +f 571/571/571 575/575/575 573/573/573 +f 576/576/576 572/572/572 574/574/574 +f 572/572/572 576/576/576 577/577/577 +f 577/577/577 576/576/576 575/575/575 +f 574/574/574 575/575/575 576/576/576 +f 580/580/580 579/579/579 578/578/578 +f 579/579/579 580/580/580 581/581/581 +f 581/581/581 580/580/580 582/582/582 +f 583/583/583 582/582/582 580/580/580 +f 582/582/582 583/583/583 577/577/577 +f 577/577/577 583/583/583 572/572/572 +f 580/580/580 572/572/572 583/583/583 +f 584/584/584 572/572/572 580/580/580 +f 585/585/585 572/572/572 584/584/584 +f 572/572/572 585/585/585 571/571/571 +f 586/586/586 571/571/571 585/585/585 +f 587/587/587 571/571/571 586/586/586 +f 571/571/571 587/587/587 575/575/575 +f 588/588/588 575/575/575 587/587/587 +f 575/575/575 588/588/588 589/589/589 +f 590/590/590 589/589/589 588/588/588 +f 590/590/590 591/591/591 589/589/589 +f 592/592/592 589/589/589 591/591/591 +f 589/589/589 592/592/592 578/578/578 +f 578/578/578 592/592/592 580/580/580 +f 593/593/593 580/580/580 592/592/592 +f 594/594/594 580/580/580 593/593/593 +f 580/580/580 594/594/594 584/584/584 +f 595/595/595 584/584/584 594/594/594 +f 584/584/584 595/595/595 596/596/596 +f 596/596/596 595/595/595 588/588/588 +f 588/588/588 595/595/595 590/590/590 +f 584/584/584 597/597/597 585/585/585 +f 597/597/597 584/584/584 598/598/598 +f 599/599/599 598/598/598 584/584/584 +f 588/588/588 598/598/598 599/599/599 +f 598/598/598 588/588/588 597/597/597 +f 587/587/587 597/597/597 588/588/588 +f 597/597/597 587/587/587 600/600/600 +f 601/601/601 600/600/600 587/587/587 +f 599/599/599 602/602/602 588/588/588 +f 603/603/603 588/588/588 602/602/602 +f 588/588/588 603/603/603 596/596/596 +f 596/596/596 603/603/603 584/584/584 +f 602/602/602 584/584/584 603/603/603 +f 584/584/584 602/602/602 599/599/599 +f 600/600/600 585/585/585 597/597/597 +f 585/585/585 600/600/600 604/604/604 +f 604/604/604 600/600/600 605/605/605 +f 601/601/601 605/605/605 600/600/600 +f 606/606/606 605/605/605 601/601/601 +f 605/605/605 606/606/606 604/604/604 +f 607/607/607 604/604/604 606/606/606 +f 608/608/608 604/604/604 607/607/607 +f 604/604/604 608/608/608 585/585/585 +f 609/609/609 585/585/585 608/608/608 +f 585/585/585 609/609/609 586/586/586 +f 586/586/586 609/609/609 587/587/587 +f 608/608/608 587/587/587 609/609/609 +f 587/587/587 608/608/608 601/601/601 +f 610/610/610 601/601/601 608/608/608 +f 601/601/601 610/610/610 606/606/606 +f 611/611/611 549/549/549 538/538/538 +f 612/612/612 549/549/549 611/611/611 +f 542/542/542 549/549/549 612/612/612 +f 549/549/549 542/542/542 613/613/613 +f 531/531/531 613/613/613 542/542/542 +f 532/532/532 613/613/613 531/531/531 +f 613/613/613 532/532/532 549/549/549 +f 100/100/100 614/614/614 99/99/99 +f 614/614/614 100/100/100 615/615/615 +f 109/109/109 615/615/615 100/100/100 +f 98/98/98 615/615/615 109/109/109 +f 615/615/615 98/98/98 614/614/614 +f 99/99/99 614/614/614 98/98/98 +f 616/616/616 589/589/589 578/578/578 +f 617/617/617 589/589/589 616/616/616 +f 582/582/582 589/589/589 617/617/617 +f 589/589/589 582/582/582 618/618/618 +f 577/577/577 618/618/618 582/582/582 +f 575/575/575 618/618/618 577/577/577 +f 618/618/618 575/575/575 589/589/589 +f 619/619/619 524/524/524 519/519/519 +f 524/524/524 619/619/619 522/522/522 +f 620/620/620 522/522/522 619/619/619 +f 522/522/522 620/620/620 521/521/521 +f 521/521/521 620/620/620 519/519/519 +f 619/619/619 519/519/519 620/620/620 +f 622/622/622 186/186/186 621/621/621 +f 186/186/186 622/622/622 182/182/182 +f 623/623/623 182/182/182 622/622/622 +f 182/182/182 623/623/623 183/183/183 +f 183/183/183 623/623/623 184/184/184 +f 624/624/624 184/184/184 623/623/623 +f 184/184/184 624/624/624 186/186/186 +f 621/621/621 186/186/186 624/624/624 +f 625/625/625 505/505/505 507/507/507 +f 505/505/505 625/625/625 514/514/514 +f 626/626/626 514/514/514 625/625/625 +f 514/514/514 626/626/626 512/512/512 +f 512/512/512 626/626/626 511/511/511 +f 625/625/625 511/511/511 626/626/626 +f 511/511/511 625/625/625 627/627/627 +f 507/507/507 627/627/627 625/625/625 +f 630/630/630 629/629/629 628/628/628 +f 631/631/631 629/629/629 630/630/630 +f 629/629/629 631/631/631 632/632/632 +f 633/633/633 632/632/632 631/631/631 +f 632/632/632 633/633/633 634/634/634 +f 635/635/635 634/634/634 633/633/633 +f 634/634/634 635/635/635 636/636/636 +f 637/637/637 636/636/636 635/635/635 +f 636/636/636 637/637/637 638/638/638 +f 639/639/639 638/638/638 637/637/637 +f 638/638/638 639/639/639 640/640/640 +f 641/641/641 640/640/640 639/639/639 +f 640/640/640 641/641/641 642/642/642 +f 643/643/643 642/642/642 641/641/641 +f 642/642/642 643/643/643 644/644/644 +f 645/645/645 644/644/644 643/643/643 +f 648/648/648 647/647/647 646/646/646 +f 649/649/649 647/647/647 648/648/648 +f 647/647/647 649/649/649 650/650/650 +f 651/651/651 650/650/650 649/649/649 +f 650/650/650 651/651/651 652/652/652 +f 653/653/653 652/652/652 651/651/651 +f 652/652/652 653/653/653 654/654/654 +f 655/655/655 654/654/654 653/653/653 +f 654/654/654 655/655/655 656/656/656 +f 657/657/657 656/656/656 655/655/655 +f 656/656/656 657/657/657 658/658/658 +f 659/659/659 658/658/658 657/657/657 +f 658/658/658 659/659/659 660/660/660 +f 661/661/661 660/660/660 659/659/659 +f 660/660/660 661/661/661 662/662/662 +f 663/663/663 662/662/662 661/661/661 +f 666/666/666 665/665/665 664/664/664 +f 665/665/665 666/666/666 667/667/667 +f 668/668/668 667/667/667 666/666/666 +f 667/667/667 668/668/668 669/669/669 +f 670/670/670 669/669/669 668/668/668 +f 669/669/669 670/670/670 671/671/671 +f 672/672/672 671/671/671 670/670/670 +f 671/671/671 672/672/672 673/673/673 +f 674/674/674 673/673/673 672/672/672 +f 673/673/673 674/674/674 675/675/675 +f 676/676/676 675/675/675 674/674/674 +f 675/675/675 676/676/676 677/677/677 +f 678/678/678 677/677/677 676/676/676 +f 677/677/677 678/678/678 679/679/679 +f 680/680/680 679/679/679 678/678/678 +f 679/679/679 680/680/680 681/681/681 +f 684/684/684 683/683/683 682/682/682 +f 683/683/683 684/684/684 685/685/685 +f 686/686/686 685/685/685 684/684/684 +f 685/685/685 686/686/686 687/687/687 +f 688/688/688 687/687/687 686/686/686 +f 687/687/687 688/688/688 689/689/689 +f 690/690/690 689/689/689 688/688/688 +f 689/689/689 690/690/690 691/691/691 +f 692/692/692 691/691/691 690/690/690 +f 691/691/691 692/692/692 693/693/693 +f 694/694/694 693/693/693 692/692/692 +f 693/693/693 694/694/694 695/695/695 +f 696/696/696 695/695/695 694/694/694 +f 695/695/695 696/696/696 697/697/697 +f 698/698/698 697/697/697 696/696/696 +f 697/697/697 698/698/698 699/699/699 +f 700/700/700 92/92/92 82/82/82 +f 78/78/78 92/92/92 700/700/700 +f 701/701/701 92/92/92 78/78/78 +f 702/702/702 92/92/92 701/701/701 +f 92/92/92 702/702/702 103/103/103 +f 703/703/703 103/103/103 702/702/702 +f 704/704/704 103/103/103 703/703/703 +f 103/103/103 704/704/704 93/93/93 +f 93/93/93 704/704/704 95/95/95 +f 705/705/705 95/95/95 704/704/704 +f 702/702/702 95/95/95 705/705/705 +f 95/95/95 702/702/702 85/85/85 +f 706/706/706 85/85/85 702/702/702 +f 78/78/78 85/85/85 706/706/706 +f 707/707/707 85/85/85 78/78/78 +f 85/85/85 707/707/707 82/82/82 diff --git a/Archer/Archer_finalrig.material b/Archer/Archer_finalrig.material new file mode 100644 index 0000000..640c846 --- /dev/null +++ b/Archer/Archer_finalrig.material @@ -0,0 +1,128 @@ + +material archer_arms +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_glove.png + filtering point point point + } + } + } +} +material archer_body +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_body.png + filtering point point point + } + } + } +} +material archer_boots +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_boots.png + filtering point point point + } + } + } +} +material archer_face +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_head01.png + filtering point point point + } + } + } +} +material archer_hair +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.423529 0.423529 0.423529 0 + emissive 0 0 0 + + texture_unit + { + texture ar_hair01_yellow.png + filtering point point point + } + } + } +} +material archer_legs +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 0.509804 0.509804 0.509804 + specular 0.137255 0.137255 0.137255 20 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_leg.png.png + filtering point point point + } + } + } +} +material default +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 0.788235 0.811765 0.690196 + specular 0.168627 0.168627 0.156863 20 + emissive 0 0 0 + } + } +} diff --git a/Archer/Archer_finalrig.mesh b/Archer/Archer_finalrig.mesh new file mode 100644 index 0000000..905d344 Binary files /dev/null and b/Archer/Archer_finalrig.mesh differ diff --git a/Archer/Archer_finalrig.mesh.material b/Archer/Archer_finalrig.mesh.material new file mode 100644 index 0000000..11ea684 --- /dev/null +++ b/Archer/Archer_finalrig.mesh.material @@ -0,0 +1,137 @@ +material +{ + technique + { + pass + { + } + } +} + +material archer_arms +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_glove.png + filtering point point point + } + } + } +} +material archer_body +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_body.png + filtering point point point + } + } + } +} +material archer_boots +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_boots.png + filtering point point point + } + } + } +} +material archer_face +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.0980392 0.0980392 0.0980392 0 + emissive 0 0 0 + + texture_unit + { + texture ar_head01.png + filtering point point point + } + } + } +} +material archer_hair +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 1 1 1 + specular 0.423529 0.423529 0.423529 0 + emissive 0 0 0 + + texture_unit + { + texture ar_hair01_yellow.png + filtering point point point + } + } + } +} +material archer_legs +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 0.509804 0.509804 0.509804 + specular 0.137255 0.137255 0.137255 20 + emissive 0 0 0 + + texture_unit + { + texture ar_ropie_d01_leg.png.png + filtering point point point + } + } + } +} +material default +{ + technique + { + pass + { + ambient 0 0 0 + diffuse 0.788235 0.811765 0.690196 + specular 0.168627 0.168627 0.156863 20 + emissive 0 0 0 + } + } +} diff --git a/Archer/Archer_finalrig.mesh.xml b/Archer/Archer_finalrig.mesh.xml new file mode 100644 index 0000000..1af0340 --- /dev/null +++ b/Archer/Archer_finalrig.mesh.xml @@ -0,0 +1,16133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archer/Archer_finalrig.mtl b/Archer/Archer_finalrig.mtl new file mode 100644 index 0000000..bb7cd07 --- /dev/null +++ b/Archer/Archer_finalrig.mtl @@ -0,0 +1,66 @@ +# Wavefront MTL +# Created by fragMOTION 1.3.5 +# http://www.fragmosoft.com + +newmtl archer_arms +illum 2 +d 1 +ka 0 0 0 +kd 1 1 1 +ks 0.0980392 0.0980392 0.0980392 +ke 0 0 0 +ns 0 +map_kd ar_ropie_d01_glove.png +newmtl archer_body +illum 2 +d 1 +ka 0 0 0 +kd 1 1 1 +ks 0.0980392 0.0980392 0.0980392 +ke 0 0 0 +ns 0 +map_kd ar_ropie_d01_body.png +newmtl archer_boots +illum 2 +d 1 +ka 0 0 0 +kd 1 1 1 +ks 0.0980392 0.0980392 0.0980392 +ke 0 0 0 +ns 0 +map_kd ar_ropie_d01_boots.png +newmtl archer_face +illum 2 +d 1 +ka 0 0 0 +kd 1 1 1 +ks 0.0980392 0.0980392 0.0980392 +ke 0 0 0 +ns 0 +map_kd ar_head01.png +newmtl archer_hair +illum 2 +d 1 +ka 0 0 0 +kd 1 1 1 +ks 0.423529 0.423529 0.423529 +ke 0 0 0 +ns 0 +map_kd ar_hair01_yellow.png +newmtl archer_legs +illum 2 +d 1 +ka 0 0 0 +kd 0.509804 0.509804 0.509804 +ks 0.137255 0.137255 0.137255 +ke 0 0 0 +ns 20 +map_kd ar_ropie_d01_leg.png.png +newmtl default +illum 2 +d 1 +ka 0 0 0 +kd 0.788235 0.811765 0.690196 +ks 0.168627 0.168627 0.156863 +ke 0 0 0 +ns 20 diff --git a/Archer/Archer_finalrig.obj b/Archer/Archer_finalrig.obj new file mode 100644 index 0000000..e59f605 --- /dev/null +++ b/Archer/Archer_finalrig.obj @@ -0,0 +1,5821 @@ +# Wavefront OBJ +# Created by fragMOTION 1.3.5 +# http://www.fragmosoft.com + +mtllib Archer_finalrig.mtl +# 1236 vertices +v 11.9294 59.9607 5.64876 +v 11.2598 59.733 5.37 +v 11.0085 57.7301 4.50211 +v 0 56.7542 -6.18747 +v -1e-006 56.4508 5.48098 +v 1e-006 50.5973 -2.53611 +v -1e-006 50.2874 2.96897 +v -2e-006 53.5428 5.55373 +v -1e-006 51.2223 4.94935 +v -2e-006 58.805 3.74267 +v -5.17809 57.3461 4.8014 +v -5.44261 60.8519 0.321916 +v -6.01387 60.2681 -4.04328 +v -3.15467 58.625 -5.62944 +v -8.63435 52.4688 2.92585 +v -8.15901 57.0734 -3.53467 +v -4.17369 54.4445 -5.28297 +v -2.04193 46.8928 3.72914 +v -6.12747 52.0847 5.50394 +v -1.76051 56.809 5.92711 +v -1.42604 53.4608 6.53542 +v -1.37113 51.018 5.41557 +v -4.00924 60.1452 2.72134 +v -2.21889 59.5563 3.88255 +v -6.63147 57.3694 1.06103 +v -2.89266 36.9351 0.157995 +v -3.8454 37.0386 3.67549 +v -7.76821 37.4516 3.47117 +v -5.89209 37.2451 -2.12407 +v -6.57932 37.4369 4.6707 +v -8.70757 37.4756 -0.301604 +v -9.98868 51.703 -3.35252 +v -9.00273 51.3482 3.10714 +v -6.16981 50.7203 5.50754 +v -1.48313 50.2096 4.43922 +v -0.387936 50.3555 -2.5236 +v -4.88285 50.9833 -5.18476 +v -0.661679 47.0475 -2.1603 +v -6.03954 50.0132 5.44456 +v -9.10805 49.8302 3.23156 +v -10.2684 49.6189 -2.81525 +v -6.20733 46.5481 5.18755 +v -9.03229 46.2427 3.3917 +v -10.1257 46.0941 -2.10534 +v -5.00364 49.7305 -4.97486 +v -5.2602 46.3958 -4.39829 +v -1.81796 47.1233 3.99413 +v -0.303147 47.3085 -2.29901 +v -5.24365 46.6795 -4.73594 +v -10.3623 46.3672 -2.32986 +v -9.27696 46.5212 3.50677 +v -6.24402 46.804 5.66113 +v -0.160275 50.1905 -2.61873 +v -1.31261 50.0606 4.55212 +v -6.11298 49.7625 5.7744 +v -9.33959 49.545 3.41161 +v -10.5652 49.4179 -2.95228 +v -5.01684 49.5065 -5.1884 +v 5.17814 57.3454 4.80147 +v 5.44261 60.8519 0.321925 +v 6.01387 60.2681 -4.04327 +v 3.15467 58.625 -5.62943 +v 8.63441 52.4677 2.92595 +v 8.15898 57.0738 -3.5347 +v 4.17366 54.4451 -5.28302 +v 2.04203 46.8912 2.72927 +v 6.12757 52.083 5.50409 +v 1.7605 56.809 5.92712 +v 1.42608 53.4601 6.53548 +v 1.37121 51.0167 5.41569 +v 4.00924 60.1451 2.72135 +v 2.21889 59.5563 3.88256 +v 6.63147 57.3693 1.06105 +v 2.8926 36.9362 -0.842091 +v 3.84548 37.0373 2.6756 +v 7.76828 37.4505 2.47128 +v 5.89192 37.2478 -3.12429 +v 6.57944 37.4349 3.67087 +v 8.70749 37.477 -1.30171 +v 9.98815 51.7052 -3.35319 +v 9.0028 51.3471 3.10724 +v 6.16994 50.7182 4.50772 +v 1.48321 50.2084 4.43933 +v 0.387892 50.3562 -2.52366 +v 4.88271 50.9856 -5.18494 +v 0.661598 47.0488 -3.1604 +v 6.03933 50.0112 4.44479 +v 9.10815 49.8285 2.23171 +v 10.2683 49.621 -3.81541 +v 6.20749 46.5456 5.18777 +v 9.03239 46.2411 2.39184 +v 10.1255 46.0962 -3.1055 +v 5.00501 49.7319 -5.97499 +v 5.26 46.399 -5.39855 +v 1.81807 47.1216 2.99428 +v 0.303063 47.3099 -3.29911 +v 5.24344 46.6828 -5.73621 +v 10.3622 46.3694 -3.33004 +v 9.27707 46.5195 2.50692 +v 6.2442 46.8011 4.66138 +v 0.160232 50.1913 -2.61878 +v 1.31269 50.0593 4.55224 +v 6.11281 49.7603 4.77464 +v 9.3397 49.5432 2.41177 +v 10.5651 49.42 -3.95245 +v 5.01826 49.508 -6.18854 +v 2e-006 53.7559 -5.43747 +v 8.6975 37.2878 -1.31222 +v 6.76057 37.5377 3.43748 +v 10.5303 46.4468 -2.28447 +v 6.62177 46.7396 4.31718 +v 10.9548 50.4704 -2.39566 +v 7.27295 50.6654 4.6959 +v 9.23463 37.8249 -0.703185 +v 7.59328 38.0484 3.34264 +v 11.1809 46.2821 -1.18733 +v 8.4895 46.4003 4.25822 +v 11.388 50.0033 -1.63276 +v 8.22053 50.078 4.5938 +v 8.42912 36.4547 1.21526 +v 10.692 50.1147 1.80544 +v 8.96295 37.0702 1.43074 +v 11.6827 46.1821 2.50399 +v 11.5135 49.582 2.29001 +v 10.3224 48.6338 -3.36357 +v 6.07508 48.8147 4.9354 +v 7.52864 48.3418 4.83329 +v 11.1263 48.2357 -2.39068 +v 11.8549 48.1736 2.53099 +v 9.68797 41.7589 -1.36643 +v 7.53984 41.8623 3.97299 +v 8.5077 41.9903 3.84464 +v 10.2718 41.9032 -0.600768 +v 10.4111 41.3889 1.97508 +v 11.1863 45.0961 -0.261639 +v 10.4811 41.8263 0.931315 +v 9.19257 45.1986 3.81395 +v 9.63646 41.8655 2.83875 +v 9.41842 45.2323 3.73643 +v 10.0911 42.1014 2.87639 +v 10.7526 41.6562 2.12198 +v 10.8582 42.0864 1.3011 +v 11.531 45.132 0.125615 +v 11.0095 45.9053 -0.925382 +v 10.5839 46.0583 -1.8196 +v 8.36601 46.021 4.15508 +v 7.00999 46.2577 4.17156 +v 9.68852 48.5899 1.3024 +v 9.81011 46.4979 1.54155 +v -8.82588 37.2864 -0.055859 +v -6.95597 37.5395 4.33167 +v -10.738 46.4453 -1.28442 +v -7.26818 46.7425 5.46837 +v -10.9549 50.4691 -1.39556 +v -7.27282 50.6675 5.69572 +v -9.23468 37.8239 0.296887 +v -7.59317 38.0502 4.34248 +v -11.181 46.2813 -0.187274 +v -8.48932 46.4032 5.25797 +v -11.388 50.0024 -0.632699 +v -8.22033 50.0812 5.59353 +v -8.4291 36.455 2.21524 +v -10.6919 50.1162 2.80532 +v -8.96292 37.0707 2.4307 +v -11.6826 46.1838 3.50385 +v -11.5134 49.5838 3.28986 +v -10.3225 48.6318 -2.36341 +v -6.07493 48.817 5.9352 +v -7.52843 48.3452 5.833 +v -11.1264 48.2343 -1.39057 +v -11.8548 48.1754 3.53083 +v -9.80129 41.7578 0.049991 +v -7.88042 41.9766 4.90366 +v -8.50755 41.9927 4.84444 +v -10.2719 41.9025 0.39928 +v -10.4111 41.39 2.97499 +v -11.1863 45.0959 0.73837 +v -10.4811 41.8267 1.93128 +v -9.1924 45.2012 4.81373 +v -9.63635 41.8672 3.8386 +v -9.41827 45.2348 4.73622 +v -10.091 42.1032 3.87625 +v -10.7525 41.6574 3.12188 +v -10.8582 42.087 2.30104 +v -11.531 45.132 1.12563 +v -11.0095 45.9046 -0.142182 +v -10.7915 46.0571 -0.819575 +v -8.36581 46.0238 5.09303 +v -7.65639 46.2606 5.32275 +v -9.68845 48.5909 2.30231 +v -9.81005 46.499 2.54146 +v -10.5442 60.6797 6.12325 +v -10.7165 60.8272 5.68257 +v -9.8977 41.8915 -0.857891 +v -10.8884 60.6666 6.11797 +v -9.75791 43.5922 -0.192364 +v -10.1969 43.5719 -0.200429 +v -9.97221 43.6773 -0.466004 +v -12.133 59.6154 8.41053 +v -12.3082 59.7986 7.98468 +v -7.22616 42.7733 -1.30693 +v -12.4661 59.5362 8.37341 +v -7.47843 44.3311 -0.377007 +v -7.90257 44.2268 -0.426226 +v -7.69075 44.4175 -0.651772 +v -12.871 59.9059 2.95462 +v -13.0301 59.9268 2.48569 +v -7.54334 40.8196 -0.116757 +v -13.2022 59.8134 2.93562 +v -7.83589 42.599 0.203616 +v -8.2575 42.4773 0.178794 +v -8.03765 42.5811 -0.091399 +v 13.0508 60.677 2.12545 +v 13.3502 60.6499 1.7314 +v 7.65736 41.646 -1.14841 +v 13.3641 60.5688 2.21949 +v 7.9562 43.432 -0.876072 +v 8.35484 43.2905 -0.756714 +v 8.23868 43.3797 -1.08943 +v 12.1492 58.397 6.15558 +v 12.474 58.4317 5.78273 +v 5.8821 40.9335 -1.44004 +v 12.448 58.2488 6.24196 +v 6.26633 42.5951 -0.773106 +v 6.64629 42.4027 -0.664357 +v 6.55976 42.5683 -0.976197 +v 11.1452 60.6056 5.85546 +v 11.47 60.7116 5.49641 +v 9.01226 42.2896 -2.01285 +v 11.4647 60.5228 5.95395 +v 9.01033 43.9881 -1.32869 +v 9.41762 43.879 -1.20454 +v 9.31073 44.0258 -1.5195 +v 12.9961 59.7124 1.84811 +v 12.3878 57.6325 1.48402 +v 11.8883 58.0559 1.35666 +v 12.0573 57.5193 5.67451 +v 11.354 55.6134 4.83718 +v 10.8226 56.2359 4.64376 +v 10.4276 58.1865 4.37427 +v -10.6812 59.8208 5.61891 +v -9.96572 60.3359 5.83276 +v -9.87598 58.2774 5.06779 +v -12.0614 58.8441 7.76957 +v -11.3657 59.2734 7.87268 +v -10.8097 57.4318 6.80956 +v -12.7725 58.9613 2.62496 +v -12.2214 59.4305 2.67064 +v -11.6193 57.3437 2.33495 +v 13.6808 59.8372 2.07893 +v 13.0725 57.7573 1.71484 +v 12.8103 57.7107 6.06007 +v 12.1071 55.8048 5.22273 +v 11.6781 57.9578 4.78088 +v -11.5068 60.2998 5.76539 +v -10.5915 57.7624 4.85395 +v -12.7864 59.0546 7.74468 +v -11.5054 57.0026 6.70646 +v -13.4868 59.175 2.64282 +v -12.1704 56.8745 2.28926 +v 12.4966 60.1358 1.72075 +v 11.5258 58.1417 5.4811 +v 10.6788 60.1894 5.24216 +v -11.4171 58.2413 5.00042 +v -12.2303 57.2131 6.68156 +v -12.8847 57.0882 2.30712 +v -6.85e-005 51.2224 4.94943 +v -6.85e-005 50.2874 2.96802 +v -6.85e-005 50.2874 2.96909 +v -6.85e-005 50.5974 -2.53616 +v -6.85e-005 56.4509 5.48093 +v -6.85e-005 56.4507 5.48103 +v 9.91493 48.6533 0.576829 +v 10.0048 48.6533 0.848872 +v 9.90957 48.6533 0.426214 +v 9.69648 48.6533 0.575217 +v 9.91071 48.6533 0.810596 +v 9.60966 48.6533 0.688167 +v 8.84474 48.6533 1.82488 +v 8.9348 48.6533 2.05989 +v 8.82836 48.6533 1.61642 +v 8.64103 48.6533 1.73479 +v 8.79685 48.6533 2.0009 +v 8.52175 48.6533 1.88325 +v 9.81113 48.6533 -0.0742695 +v 9.90959 48.6533 0.167032 +v 9.79952 48.6533 -0.228078 +v 9.59191 48.6533 -0.0853702 +v 9.8033 48.6533 0.132281 +v 9.49869 48.6533 0.0326982 +v -9.8575 48.6533 0.975239 +v -10.0191 48.6533 1.16091 +v -9.78535 48.6533 0.81076 +v -9.65073 48.6533 1.00096 +v -9.89232 48.6533 1.16243 +v -9.59724 48.6533 1.16596 +v -9.02867 48.6533 1.8768 +v -9.22206 48.6533 2.11806 +v -8.96236 48.6533 1.72662 +v -8.82806 48.6533 1.95957 +v -9.11943 48.6533 2.11564 +v -8.79467 48.6533 2.10799 +v -10.2405 48.6533 1.46238 +v -10.4024 48.6533 1.6777 +v -10.1882 48.6533 1.31799 +v -10.0394 48.6533 1.53283 +v -10.3001 48.6533 1.67783 +v -9.9908 48.6533 1.67824 +v -8.69162 48.6533 3.30449 +v -6.57927 48.6533 5.89974 +v -11.739 48.6533 3.44907 +v -9.72948 48.6533 2.32288 +v -10.3279 48.6533 -2.28845 +v -10.9435 48.6533 4.04805 +v -7.65122 48.6533 5.79051 +v -11.7327 48.6533 2.4418 +v -11.1884 48.6533 -1.21096 +v -10.3392 48.6533 -2.33622 +v -6.23867 48.6533 5.88927 +v -7.49452 48.6533 5.81479 +v -10.3299 48.6533 -2.35207 +v -6.16909 48.6533 5.89836 +v 8.66956 48.6533 2.32687 +v 6.57121 48.6533 4.90054 +v 11.7386 48.6533 2.44891 +v 9.73023 48.6533 1.32331 +v 10.3272 48.6533 -3.2955 +v 10.9395 48.6533 3.0506 +v 7.65275 48.6533 4.79033 +v 11.7325 48.6533 1.4393 +v 11.1881 48.6533 -2.21162 +v 10.3375 48.6533 -3.33892 +v 6.23647 48.6533 4.89013 +v 7.49437 48.6533 4.81487 +v 10.3291 48.6533 -3.35329 +v 6.11759 48.6533 4.88732 +v 8.3351 48.6533 3.14185 +v 6.16197 48.6533 4.73227 +v 9.32127 48.6533 2.43977 +v 10.5141 48.6533 -3.79601 +v 9.6264 48.6533 0.801787 +v 5.08639 48.6533 -6.05169 +v 9.07434 48.6533 -4.45213 +v 3.18486 48.6533 -5.06505 +v 0.796383 48.6533 0.0485653 +v 0.236469 48.6533 -3.44816 +v 4.31101 48.6533 4.02771 +v 1.55457 48.6533 3.28519 +v -8.33251 48.6533 4.14345 +v -6.16211 48.6533 5.73193 +v -9.32112 48.6533 3.43967 +v -10.5143 48.6533 -2.79628 +v -9.62658 48.6533 1.80047 +v -5.08529 48.6533 -5.05185 +v -9.07934 48.6533 -3.4503 +v -3.18714 48.6533 -4.06683 +v -0.79641 48.6533 1.04872 +v -0.236481 48.6533 -2.44819 +v -4.30786 48.6533 5.02618 +v -1.55474 48.6533 4.28477 +v -16.9917 68.9766 3.45727 +v -17.3172 71.0788 2.67715 +v -17.8686 70.559 -0.071285 +v -18.402 68.4582 -0.599625 +v -17.8928 66.8401 1.70563 +v -19.3249 67.8259 4.30806 +v -20.7753 70.2576 3.47008 +v -20.9827 69.9969 -0.247348 +v -20.6003 67.2102 -0.870863 +v -19.9517 65.3263 1.87824 +v -30.3351 64.1286 3.20357 +v -30.8472 64.7998 2.68333 +v -30.775 64.668 0.436094 +v -30.3931 63.8323 0.435904 +v -30.256 63.0926 2.56148 +v -35.4738 62.8525 3.05978 +v -35.1309 62.6218 -0.007645 +v -33.5458 61.5391 -0.219289 +v -34.369 61.2962 3.75094 +v -30.1317 62.9085 1.02219 +v -33.8646 61.1776 0.331807 +v -32.0307 60.7546 -0.670539 +v -31.8894 59.8327 -0.407654 +v -33.4022 59.856 -0.19177 +v -33.542 60.6479 -0.492836 +v -33.7361 59.1113 -1.36183 +v -33.7491 58.6542 -1.04443 +v -34.0059 58.8275 -0.552466 +v -34.0369 59.2588 -0.813116 +v -36.2791 60.1408 3.52766 +v -37.228 60.9009 2.98027 +v -36.8936 60.8276 0.024515 +v -35.8792 60.0611 -0.186059 +v -36.6969 57.8266 3.10717 +v -37.2531 57.6993 2.60876 +v -36.9265 57.633 0.364722 +v -36.285 57.7322 0.107632 +v -19.1066 70.5858 3.12795 +v -18.0907 68.5981 4.02562 +v -15.2295 68.2161 1.84153 +v -15.6177 69.7096 3.62324 +v -15.6536 69.216 -0.209819 +v -16.453 71.1271 0.475894 +v -16.5127 71.3337 2.80696 +v -13.6524 67.914 1.75894 +v -14.3154 70.2803 3.94552 +v -14.2858 69.6525 -0.640633 +v -15.5689 72.25 0.157693 +v -15.4307 72.323 2.85873 +v -15.8029 69.5887 1.56754 +v 16.9917 68.9761 3.45711 +v 17.3172 71.0788 2.67716 +v 17.8686 70.56 -0.070579 +v 18.402 68.4654 -0.601067 +v 17.8928 66.8399 1.70146 +v 19.3249 67.8139 4.30523 +v 20.7753 70.2497 3.47832 +v 20.9827 70.0078 -0.236727 +v 20.6003 67.2248 -0.874888 +v 19.9517 65.3246 1.86195 +v 30.3351 64.1181 3.20544 +v 30.8472 64.7927 2.6901 +v 30.775 64.6755 0.442006 +v 30.3931 63.8398 0.436346 +v 30.256 63.0864 2.55752 +v 35.4738 62.8508 3.06109 +v 35.1309 62.6252 -0.005945 +v 33.5458 61.5508 -0.223803 +v 34.369 61.2923 3.74986 +v 30.1317 62.9122 1.01695 +v 33.8646 61.1817 0.328888 +v 32.0307 60.7693 -0.682975 +v 31.8894 59.8458 -0.42546 +v 33.4022 59.8677 -0.205852 +v 33.542 60.6615 -0.502258 +v 33.7361 59.1305 -1.37916 +v 33.7491 58.6714 -1.06423 +v 34.0059 58.8414 -0.570714 +v 34.0368 59.2744 -0.828935 +v 36.2791 60.1408 3.52767 +v 37.228 60.9009 2.98028 +v 36.8936 60.8276 0.02452 +v 35.8792 60.0611 -0.186054 +v 36.6969 57.8266 3.10717 +v 37.2531 57.6993 2.60876 +v 36.9265 57.633 0.364727 +v 36.285 57.7322 0.107638 +v 19.1066 70.5808 3.13315 +v 18.0907 68.5902 4.02419 +v 15.2295 68.2161 1.84153 +v 15.6177 69.7096 3.62324 +v 15.6536 69.216 -0.20982 +v 16.453 71.1271 0.475898 +v 16.5127 71.3337 2.80696 +v 13.6524 67.914 1.75894 +v 14.3154 70.2803 3.94552 +v 14.2858 69.6525 -0.64063 +v 15.5689 72.25 0.157694 +v 15.4307 72.323 2.85873 +v 15.8029 69.5887 1.56754 +v -6.6176 31.504 5.40027 +v -8.82169 30.7841 3.41906 +v -8.62009 31.1153 0.205381 +v -6.1506 31.5442 -2.37373 +v -3.19477 30.6417 0.820142 +v -4.02495 30.8742 3.79922 +v -7.34547 11.8166 5.34374 +v -8.80372 11.3598 3.8717 +v -8.56565 11.497 2.06259 +v -7.54628 11.9341 1.07143 +v -5.9174 11.1306 1.96564 +v -5.8797 11.2367 3.90979 +v -6.68413 27.6473 6.66533 +v -9.6807 25.4862 4.20782 +v -9.24079 25.5682 1.11196 +v -6.68122 25.4414 0.010075 +v -3.54492 25.3914 1.53647 +v -3.51897 26.2446 4.72026 +v -6.05593 35.4927 -2.8701 +v -6.29909 28.7681 -0.771754 +v -7.82807 -0.053949 5.2429 +v -8.27133 -0.017583 4.66314 +v -8.33667 -0.035207 4.03527 +v -7.58666 -0.084154 3.93986 +v -7.54307 -0.069251 4.58117 +v -10.498 2.97937 -1.8867 +v -8.27546 3.7359 -2.61626 +v -6.21649 2.61519 -2.13538 +v -6.11314 0.047383 -0.530513 +v -10.7553 0.169275 0.044228 +v -9.66426 5.89963 2.80534 +v -5.90823 6.1348 2.58171 +v -9.34678 6.92579 4.65417 +v -7.3707 6.90309 6.27376 +v -5.77658 6.96715 4.64598 +v -9.39783 1.02399 -5.27737 +v -8.13328 1.83022 -5.12201 +v -7.19576 0.849266 -5.6863 +v -7.18826 -0.002046 -5.83336 +v -9.40097 0.049213 -5.41906 +v -9.53608 6.8735 -0.044014 +v -7.91564 7.8463 -0.827051 +v -6.07397 6.28152 -0.116393 +v -9.8727 3.09585 1.60007 +v -6.28409 3.027 1.25935 +v -1.91182 36.9508 -0.918642 +v -3.34447 36.8245 3.57525 +v -9.20396 37.2214 3.29169 +v -5.8931 37.4206 -4.28543 +v -6.69004 37.2069 4.86494 +v -9.66466 37.491 -0.285066 +v -0.694575 43.8418 -2.88539 +v -0.925659 43.2294 5.4271 +v -11.4058 43.435 4.92988 +v -5.52628 44.3424 -6.72201 +v -6.51076 43.3219 7.12145 +v -11.1096 44.2267 -2.3436 +v -9.63503 37.4797 1.58473 +v -2.15335 36.9897 1.38673 +v -1.27662 41.5288 -1.87415 +v -6.63831 40.8811 6.55685 +v -5.68704 42.084 -6.36242 +v -10.291 41.9779 -1.92997 +v -10.2732 41.0265 4.01397 +v -1.44606 40.6718 4.53684 +v -6.83892 23.4873 7.02985 +v -9.32471 20.0929 3.92004 +v -8.92288 20.2788 1.84022 +v -6.80258 20.1733 0.686469 +v -4.49708 19.0975 1.49166 +v -4.6842 18.916 4.24801 +v -7.09339 19.0835 5.8976 +v -8.77995 3.40776 3.6122 +v -6.92377 3.48238 3.48475 +v -8.62226 3.59474 4.54415 +v -7.62566 3.70725 5.47856 +v -6.85159 3.60708 4.4491 +v -7.35721 9.74825 6.05341 +v -5.88656 38.0168 1.5868 +v 6.61774 31.5018 5.40044 +v 8.82174 30.7833 3.41913 +v 8.62001 31.1166 0.205271 +v 6.15041 31.5473 -2.37399 +v 3.19471 30.6428 0.820054 +v 4.02502 30.8732 3.7993 +v 7.34551 11.8162 5.34378 +v 8.80372 11.3598 3.8717 +v 8.56562 11.4976 2.06254 +v 7.54623 11.935 1.07136 +v 5.91737 11.1312 1.96559 +v 5.87971 11.2368 3.90978 +v 6.68431 27.6446 6.66556 +v 9.68077 25.4851 4.20791 +v 9.24074 25.5692 1.11188 +v 6.68112 25.4432 0.009923 +v 3.54486 25.3923 1.5364 +v 3.51906 26.2434 4.72037 +v 6.05573 35.496 -3.87037 +v 6.29896 28.7702 -0.771934 +v 7.82808 -0.053949 5.2429 +v 8.27134 -0.017583 4.66314 +v 8.33667 -0.035207 4.03527 +v 7.58667 -0.084154 3.93987 +v 7.54308 -0.069251 4.58117 +v 10.498 2.97937 -1.88669 +v 8.27546 3.7359 -2.61626 +v 6.21649 2.61519 -2.13538 +v 6.11315 0.047382 -0.530512 +v 10.7553 0.169275 0.044225 +v 9.66426 5.89963 2.80534 +v 5.90824 6.1348 2.58171 +v 9.34679 6.92579 4.65417 +v 7.37071 6.90309 6.27376 +v 5.77659 6.96716 4.64598 +v 9.39784 1.02399 -5.27737 +v 8.13329 1.83022 -5.12201 +v 7.19576 0.849267 -5.6863 +v 7.18826 -0.002046 -5.83336 +v 9.40098 0.049213 -5.41906 +v 9.53609 6.8735 -0.044012 +v 7.91565 7.8463 -0.827051 +v 6.07397 6.28152 -0.116392 +v 9.8727 3.09585 1.60007 +v 6.28409 3.02701 1.25935 +v 1.91171 36.9527 -1.9188 +v 3.34455 36.8233 2.57535 +v 9.20403 37.2204 2.29178 +v 5.89285 37.4247 -5.28577 +v 6.69017 37.2048 3.86512 +v 9.66458 37.4924 -1.28517 +v 0.694399 43.8446 -3.88562 +v 0.925837 43.2266 4.42733 +v 11.4059 43.4324 3.93008 +v 5.52595 44.3478 -7.72246 +v 6.51101 43.3179 6.12178 +v 11.1094 44.2291 -3.34379 +v 9.63503 37.4798 0.584726 +v 2.15333 36.99 0.386706 +v 1.27648 41.5311 -2.87433 +v 6.63853 40.8776 5.55714 +v 5.68671 42.0893 -7.36285 +v 10.2908 41.9801 -2.93015 +v 10.2733 41.0247 3.01411 +v 1.44619 40.6697 3.53701 +v 6.8391 23.4846 7.03009 +v 9.32475 20.0924 3.92008 +v 8.92283 20.2796 1.84015 +v 6.80248 20.1749 0.686328 +v 4.49701 19.0988 1.49155 +v 4.68424 18.9155 4.24805 +v 7.0935 19.0818 5.89775 +v 8.77996 3.40776 3.6122 +v 6.92378 3.48238 3.48475 +v 8.62227 3.59474 4.54415 +v 7.62566 3.70725 5.47856 +v 6.85159 3.60708 4.4491 +v 7.35723 9.74815 6.05342 +v 5.88656 38.0168 0.586796 +v -2.70683 90.1592 -6.64395 +v -4.02625 90.9128 -5.80914 +v -2.81708 89.7845 -6.66527 +v -5.56005 84.9001 7.88776 +v -5.75679 88.5358 8.85085 +v 2e-005 93.9826 -5.74762 +v -4.3505 92.7145 -4.86687 +v 0.005175 98.0596 0.205212 +v -6.16974 95.6673 1.05322 +v -6.06694 95.4784 5.69854 +v 0.005 98.0633 6.23052 +v -5.39773 85.9426 2.69979 +v -8.23796 85.7183 3.97756 +v -7.43849 92.9802 5.14822 +v -7.41455 92.3406 1.91884 +v -5.53976 89.8814 -3.43098 +v -2.62082 93.5081 -5.33541 +v -3.9791 97.5525 0.592259 +v -2.66544 97.4564 6.16137 +v -7.5679 88.4369 6.9564 +v -8.2258 88.4523 4.64628 +v -7.08005 88.3554 1.84482 +v -2.91839 88.6237 9.94576 +v -2.93287 75.2508 -4.62143 +v -2.88038 84.6758 8.84396 +v 0.005066 96.2803 -3.56719 +v -3.20101 96.0165 -3.08375 +v -5.14065 94.7154 -1.99115 +v -6.67587 91.4818 -1.01264 +v -6.90764 88.251 -0.179923 +v -6.69131 86.2145 -0.540538 +v -5.48851 80.594 4.43297 +v -5.89834 81.2508 0.777554 +v -7.35206 80.9262 1.75231 +v -2.92414 80.3214 5.69783 +v -5.15515 93.6808 8.06487 +v -2.86889 93.923 9.34873 +v 9.8e-005 94.1629 9.85288 +v -3.71782 77.1359 0.743221 +v -4.56207 78.2566 -2.27605 +v -6.25324 77.521 -1.30618 +v -7.43515 85.1557 6.35049 +v -2.75273 70.4395 -6.97061 +v -2.07397 74.4252 -5.17425 +v -3.27993 73.3064 -3.81774 +v -3.27348 74.6033 -5.3873 +v -4.69673 74.2329 -4.32651 +v -6.0677 86.1995 0.991793 +v -3.06961 77.7833 -2.93019 +v -4.03594 80.2397 -1.64992 +v -4.35561 80.1825 -2.2073 +v -3.44514 77.7576 -3.38224 +v -5.42607 82.8379 -1.40741 +v -5.26487 82.9099 -0.614345 +v -5.75319 87.9129 -1.70949 +v -4.6048 72.1299 -5.67525 +v -2.83342 78.0021 -3.59028 +v -3.59488 80.4249 -2.75994 +v -4.65349 82.9989 -2.1278 +v -5.57958 86.2739 -1.78431 +v -2.79286 77.8981 -1.69748 +v -5.31271 90.7834 0.956975 +v -3.54618 71.3478 -6.69036 +v -4.38775 70.2363 -6.08157 +v -5.52317 76.9574 -0.201776 +v 1.8e-005 84.636 9.35844 +v 1.8e-005 89.3151 10.6281 +v -1.54456 82.6953 7.75348 +v -5.14515 71.3985 -5.70398 +v -4.83711 70.5884 -6.71908 +v -3.87666 69.721 -6.99934 +v -5.28724 70.2427 -6.11029 +v -2.71237 79.3726 0.748224 +v -4.3148 81.2181 0.015133 +v -1.31383 98.246 0.337848 +v 5.56009 84.9001 7.88776 +v 5.75683 88.5358 8.85085 +v 4.35053 92.7145 -4.86687 +v 6.17981 95.6666 1.05322 +v 6.07665 95.4778 5.69854 +v 5.45798 85.9426 2.69979 +v 8.31449 85.7183 3.97756 +v 7.43868 92.9802 5.14822 +v 7.41459 92.3406 1.91884 +v 5.53012 89.8261 -3.43098 +v 2.62086 93.5081 -5.33541 +v 3.98939 97.5517 0.592263 +v 2.67536 97.456 6.16137 +v 7.56793 88.4369 6.9564 +v 8.19598 88.4523 4.64628 +v 7.08008 88.3554 1.84482 +v 2.91843 88.6237 9.94576 +v 2.93291 75.2508 -4.62143 +v 2.88042 84.6758 8.84396 +v 3.21111 96.0162 -3.08375 +v 5.1506 94.715 -1.99115 +v 6.67591 91.4818 -1.01264 +v 6.90767 88.251 -0.179922 +v 6.75156 86.2145 -0.540536 +v 5.48855 80.594 4.43297 +v 5.89838 81.2508 0.777553 +v 7.44351 80.9261 1.75234 +v 2.92418 80.3214 5.69783 +v 5.15535 93.6808 8.06487 +v 2.86908 93.923 9.34873 +v 3.71786 77.1359 0.74322 +v 4.5621 78.2566 -2.27605 +v 6.07596 77.521 -1.30618 +v 7.43519 85.1557 6.35049 +v 2.84465 72.1228 -5.95266 +v 3.36905 74.3118 -5.17425 +v 4.2466 73.1928 -3.81775 +v 4.43154 74.4898 -5.3873 +v 5.92445 74.1194 -4.32651 +v 6.12794 86.1995 0.991792 +v 3.06964 77.7833 -2.93019 +v 4.03598 80.2397 -1.64992 +v 4.35565 80.1825 -2.2073 +v 3.44518 77.7576 -3.38224 +v 5.54904 82.8379 -1.40741 +v 5.38784 82.9099 -0.614347 +v 5.73111 87.9129 -1.70949 +v 4.69138 71.2939 -6.15854 +v 2.83345 78.0021 -3.59028 +v 3.59491 80.4249 -2.75994 +v 4.77646 82.9989 -2.1278 +v 5.63983 86.2739 -1.78431 +v 2.7929 77.8981 -1.69748 +v 5.31275 90.7834 0.956974 +v 3.74851 71.8471 -6.2915 +v 2.98549 70.6752 -6.10632 +v 5.5232 76.9574 -0.201775 +v 1.5446 82.6953 7.75348 +v 3.90858 70.3405 -6.70821 +v 3.20169 70.7799 -6.92767 +v 2.70238 71.0997 -6.50157 +v 2.46908 69.8981 -7.11745 +v 2.71241 79.3726 0.748224 +v 4.31484 81.2181 0.015132 +v 1.32418 98.2458 0.337849 +v 1.6e-005 90.5032 -6.89877 +v -4.07588 89.927 -5.84231 +v -1.90777 90.3337 -6.67587 +v 1.5e-005 91.6683 -6.64335 +v -2.14477 91.5536 -6.38729 +v -4.16334 91.1966 -5.49367 +v -5.01238 89.7498 -4.3629 +v -5.34377 89.5623 -3.59325 +v 4.02095 89.9276 -5.84231 +v 1.9078 90.3337 -6.67587 +v 2.04783 91.5544 -6.38729 +v 4.23047 91.3083 -5.54253 +v 4.99243 89.6576 -4.3629 +v 5.3367 89.6382 -3.59325 +v -5.36853 81.7123 0.556355 +v -5.80972 81.0234 0.325977 +v -6.25727 81.7123 0.556357 +v -5.8129 81.8756 0.183542 +v -5.80972 83.3755 1.12007 +v -5.8582 81.6296 0.932756 +v 5.36867 81.7123 0.556355 +v 5.80987 81.0234 0.325978 +v 6.25742 81.7123 0.556355 +v 5.81305 81.8756 0.183542 +v 5.80987 83.3755 1.12008 +v 5.85835 81.6296 0.932757 +v 7.9e-005 89.985 10.5491 +v -1.00397 92.8496 9.85031 +v 0.000158 92.9889 10.5666 +v 0.00016 93.9423 9.91296 +v 1.00429 92.8496 9.85031 +v 7.6e-005 87.2489 -6.99263 +v -1.02243 89.2163 -6.94022 +v 7.3e-005 89.2306 -7.41492 +v 7.7e-005 90.3361 -6.91201 +v 1.02258 89.2163 -6.94022 +v 0.762824 88.782 -6.9589 +v 0.816276 89.2538 -6.91364 +v 2.70683 90.1592 -6.64395 +v 2.81777 89.7954 -6.66527 +v 4.264 90.7358 -5.7121 +v 4.46896 91.272 -5.13639 +v 4.58717 90.9788 -4.96828 +v -4.17946 90.598 -5.8003 +v -4.46629 91.2502 -4.95163 +v 4.1388 91.0734 -5.72095 +v -0.762825 88.782 -6.9589 +v -0.816277 89.2538 -6.91364 +v -4.65375 90.9431 -4.79372 +v 4.8e-005 85.7165 -6.72421 +v 4.9e-005 84.3311 -7.47266 +v 5e-005 83.1421 -6.68244 +v 7.3e-005 89.8805 -6.95786 +v 7.1e-005 88.0111 -6.97556 +v 7.5e-005 93.7831 -5.59437 +v 5e-005 82.3007 -6.58634 +v 4.7e-005 79.9918 -5.29238 +v 4.9e-005 79.6284 -4.48555 +v 4.9e-005 86.1626 7.4578 +v 4.9e-005 82.5209 4.24809 +v 1.8e-005 76.6928 4.96919 +v 4.9e-005 80.0001 -1.05346 +v 1.9e-005 76.0132 0.034039 +v 4.8e-005 81.9246 -6.29311 +v -1.88423 85.6518 -5.44187 +v -2.05758 86.7067 -5.66352 +v -2.99432 87.3871 -5.64043 +v -0.747577 85.7196 -6.38049 +v -1.11071 87.3944 -6.56314 +v -2.77754 88.9382 -6.58351 +v -3.87217 87.1868 -5.19217 +v -4.24538 89.1504 -5.70636 +v -4.24108 86.6122 -4.85471 +v -5.35277 87.4117 -3.82514 +v -4.28761 85.8864 -4.73691 +v -5.27871 86.0541 -3.23671 +v -1.10783 83.8618 -6.34078 +v -2.41644 83.92 -5.5819 +v -2.72111 85.4886 -5.39253 +v -3.90661 84.0138 -5.05696 +v -3.73075 85.5352 -5.00594 +v -4.93432 84.4761 -3.17572 +v -1.51824 82.0506 -5.7409 +v -3.53447 82.2545 -4.69701 +v -4.26975 82.4591 -2.55563 +v -3.40959 91.17 -5.81075 +v -5.51579 90.1202 -3.22141 +v -4.17325 92.9164 -4.65729 +v -1.31218 80.1886 -4.75654 +v -2.38917 80.4941 -3.76938 +v -6.1265 86.1587 0.975676 +v -3.73834 81.4777 -0.997722 +v -1.24628 79.9086 -3.00658 +v -4.8024 82.8779 0.321007 +v -2.92888 81.0665 -0.382558 +v -2.96244 82.7983 1.33944 +v -6.6384 87.923 2.31405 +v -6.01525 85.1901 3.43467 +v -3.66248 86.4011 6.6991 +v -2.19039 82.3944 3.42103 +v -2.2718 76.7305 4.02803 +v -2.79963 76.5982 2.30771 +v -1.41649 80.531 -0.576808 +v -1.63428 76.0611 0.501596 +v -6.29195 88.1371 2.85194 +v 5.1e-005 81.5135 -6.059 +v -1.53719 81.6255 -5.55945 +v 4.8e-005 82.0765 -6.29811 +v 4.9e-005 82.8537 -6.56331 +v -1.39582 82.5253 -5.8837 +v -1.76519 82.534 -5.7088 +v -2.48953 93.6715 -5.12583 +v -6.39622 83.3162 1.50751 +v -7.00174 86.7358 2.61172 +v -7.99205 85.0948 3.268 +v -12.0346 91.3302 5.47454 +v -9.77824 89.4635 4.60615 +v -10.3436 88.9333 4.5022 +v -9.73404 88.9496 5.20937 +v -9.43403 89.8919 4.64907 +v -7.48468 88.32 2.94152 +v -7.07792 86.2773 4.11271 +v 1.88433 85.6518 -5.44187 +v 2.05768 86.7067 -5.66352 +v 2.99442 87.3871 -5.64043 +v 0.74767 85.7196 -6.3805 +v 1.1108 87.3944 -6.56314 +v 2.77768 88.9382 -6.58351 +v 3.87226 87.1868 -5.19217 +v 4.24553 89.1503 -5.70636 +v 4.24118 86.6122 -4.85471 +v 5.35287 87.4117 -3.82514 +v 4.28771 85.8864 -4.73691 +v 5.27881 86.0541 -3.23671 +v 1.10793 83.8618 -6.34078 +v 2.41653 83.92 -5.5819 +v 2.72121 85.4886 -5.39253 +v 3.90671 84.0138 -5.05696 +v 3.73084 85.5352 -5.00594 +v 4.99975 84.4761 -3.17572 +v 1.50912 82.0506 -5.7409 +v 3.52535 82.2545 -4.69701 +v 4.26059 82.4591 -2.55563 +v 3.40974 91.17 -5.81075 +v 5.51032 90.0652 -3.22141 +v 4.17329 92.9164 -4.6573 +v 1.30306 80.1886 -4.75654 +v 2.38005 80.4941 -3.76938 +v 6.1266 86.1587 0.975676 +v 3.72919 81.4777 -0.997723 +v 1.23716 79.9086 -3.00658 +v 4.79797 82.8779 0.321004 +v 2.91976 81.0665 -0.382558 +v 2.96254 82.7983 1.33944 +v 6.63855 87.923 2.31405 +v 6.01535 85.1901 3.43467 +v 3.66258 86.4011 6.6991 +v 2.19049 82.3944 3.42103 +v 2.27183 76.7305 4.02803 +v 2.79967 76.5982 2.30771 +v 1.52719 80.531 -0.576809 +v 1.63432 76.0611 0.501596 +v 6.2921 88.1371 2.85194 +v 1.52807 81.6255 -5.55945 +v 1.3867 82.5252 -5.8837 +v 1.75607 82.534 -5.7088 +v 2.48957 93.6715 -5.12583 +v 6.39637 83.3162 1.5075 +v 7.00188 86.7358 2.61172 +v 7.9922 85.0948 3.268 +v 12.0347 91.3302 5.47455 +v 9.77839 89.4635 4.60615 +v 10.3437 88.9333 4.5022 +v 9.73418 88.9496 5.20937 +v 9.43417 89.8919 4.64907 +v 7.48482 88.3199 2.94152 +v 7.07806 86.2773 4.11271 +v 0 77.942 4.9878 +v 0 83.8971 9.82726 +v -6.50179 81.9049 6.47306 +v -4.05924 83.3715 8.65527 +v -2.45339 77.9167 4.30314 +v -6.91255 79.9381 3.87462 +v -3.03503 75.7209 -1.18522 +v -5.3583 78.0418 2.02826 +v -4.04852 76.8626 0.874052 +v 0 79.5344 6.39385 +v 1e-006 77.0776 -0.560749 +v 0 72.7717 5.57858 +v 1e-006 68.1774 -4.63749 +v 0 75.1065 -2.04582 +v 0 77.2149 5.94482 +v 1e-006 69.604 -4.38678 +v -1e-006 72.7605 -3.54873 +v 0 67.5008 3.62857 +v 0 79.3983 6.67046 +v 1e-006 71.0218 -4.07832 +v 0.572154 56.0855 -6.69666 +v 3e-006 58.6621 5.15081 +v -1e-006 63.4102 2.44887 +v 0 62.5303 -5.53421 +v -7.5e-007 53.0577 -7.18655 +v -2.125e-006 48.861 -7.40292 +v 0.000232 55.514 6.96655 +v 0 51.9366 8.53514 +v 0 48.7808 9.21983 +v -5e-007 50.4968 -7.32854 +v -1.58599 77.4014 -0.046317 +v -6.89787 72.9475 4.99648 +v -5.62586 67.9618 -2.15349 +v -3.26016 73.0804 5.60671 +v -3.97709 67.3271 -4.05723 +v -5.73711 76.8848 4.40086 +v -2.81132 77.4595 5.63592 +v -5.2448 75.9472 -0.093215 +v -6.37889 68.8013 -2.33704 +v -4.90368 68.2988 -5.85813 +v -6.13658 73.7049 -1.89632 +v -4.52199 73.1998 -3.79058 +v -1.5894 75.4158 -1.69655 +v -1.58174 73.008 -4.89011 +v -2.55083 68.4751 -6.56477 +v -1.93296 67.4477 -4.98088 +v -5.59009 67.8208 2.05855 +v -2.99593 67.6371 3.87788 +v -6.59993 70.3162 1.02219 +v -7.59585 70.9089 1.19026 +v -8.65556 72.889 -1.64568 +v -9.72166 75.5695 -0.203568 +v -9.62603 76.2066 4.06864 +v -9.53729 72.4465 4.46923 +v -10.872 72.3048 -1.32847 +v -12.8553 73.8732 -0.007973 +v -12.4881 73.8697 4.34047 +v -6.63864 76.0427 -0.297926 +v -6.73742 76.5658 4.06231 +v -0.17221 78.9819 -0.766734 +v -1.8004 79.4683 -0.21673 +v -5.03455 78.8748 4.59291 +v -2.6826 79.3323 6.2007 +v -6.75379 70.7195 -2.31767 +v -5.3431 70.3757 -5.91889 +v -2.75252 70.6518 -6.78095 +v -15.4878 69.7138 3.46285 +v -16.4828 71.2031 2.75554 +v -1.75119 66.6301 -4.90204 +v -3.41758 65.811 -4.85824 +v -4.93953 65.1074 -3.24588 +v -5.32987 65.9527 -0.014634 +v -12.9007 73.1722 0.062803 +v -12.6592 72.7719 3.71933 +v -16.3747 72.5152 0.554237 +v -16.0157 72.3028 4.64492 +v -19.5474 72.028 0.546918 +v -19.0336 71.7426 5.10955 +v -16.1723 71.9212 -0.269818 +v -18.4447 70.9358 -1.39134 +v -15.432 71.6715 5.31037 +v -17.7215 70.3551 6.26187 +v -14.0653 72.9572 4.48277 +v -14.4938 73.0101 0.068066 +v -14.2562 70.2529 6.40722 +v -15.33 70.9056 -2.36181 +v -15.9035 68.1527 7.71938 +v -17.0802 69.5834 -3.2279 +v -16.7938 65.9584 9.66525 +v -18.2066 67.9716 -4.74696 +v -22.2463 71.2721 -0.068437 +v -19.1093 67.7728 8.40727 +v -20.1353 69.164 -3.42392 +v -21.4869 70.6375 6.38391 +v -12.0882 71.4467 5.521 +v -2.81357 63.4025 1.94246 +v -4.50946 63.5634 0.58848 +v -4.52326 63.556 -3.5945 +v -15.2588 68.2941 1.83466 +v -15.6633 69.2478 -0.122035 +v -16.4259 71.0708 0.532036 +v -5.89822 60.8322 0.32173 +v -6.46948 60.269 -4.09688 +v -4.82133 58.7687 -5.7897 +v -4.46485 59.9089 3.1319 +v -2.21889 59.3982 4.24378 +v -2.30795 63.0356 -4.94981 +v -4.6474 54.7911 -6.35129 +v -5.44372 50.2061 -6.7519 +v -4.74687 57.3047 5.58187 +v -5.47582 53.2446 7.3002 +v -5.99292 50.5808 7.98182 +v -5.02584 52.3358 -6.5235 +v -22.3832 71.7909 3.44462 +v -20.211 69.0656 7.62789 +v -21.4198 70.4732 -2.07425 +v -4.57724 56.6658 -6.09165 +v -5.52547 59.6511 -4.94131 +v -4.54667 58.7216 4.57794 +v -2.59853 56.3564 6.34423 +v -2.75806 52.4465 7.99651 +v -2.8966 49.5192 8.53818 +v -10.4995 71.8205 -1.39724 +v -9.60696 71.8131 4.03 +v -9.70956 74.6658 4.68936 +v -6.98997 72.1468 4.36944 +v -13.2927 71.7102 -1.84833 +v 0 81.8669 4.70652 +v -2.45339 81.3965 3.93635 +v -3.34147 80.506 1.55171 +v -2.98003 77.762 1.77544 +v -3.19204 75.5801 1.3266 +v -4.93023 77.3726 4.36818 +v -5.18785 77.2259 2.16219 +v 6.50179 81.9049 6.47306 +v 4.05924 83.3715 8.65527 +v 2.45339 77.9167 4.30314 +v 6.91255 79.9381 3.87462 +v 3.03503 75.721 -1.18522 +v 5.3583 78.0418 2.02826 +v 4.04853 76.8626 0.874055 +v 1.58599 77.4014 -0.046317 +v 6.89787 72.9475 4.99648 +v 5.62586 67.9618 -2.15349 +v 3.26016 73.0804 5.60671 +v 3.97709 67.3271 -4.05723 +v 5.73711 76.8848 4.40086 +v 2.81132 77.4596 5.63592 +v 5.2448 75.9472 -0.093214 +v 6.37889 68.8013 -2.33705 +v 4.90368 68.2988 -5.85813 +v 6.13658 73.7049 -1.89632 +v 4.52199 73.1998 -3.79058 +v 1.5894 75.4158 -1.69655 +v 1.58174 73.008 -4.89011 +v 2.55083 68.4751 -6.56477 +v 1.93296 67.4477 -4.98088 +v 5.59009 67.8208 2.05855 +v 2.99593 67.6371 3.87788 +v 6.59993 70.3162 1.0222 +v 7.59585 70.9089 1.19026 +v 8.65555 72.889 -1.69524 +v 9.72166 75.5695 -0.203567 +v 9.62603 76.2066 4.06864 +v 9.53729 72.4465 4.50042 +v 10.872 72.3048 -1.22628 +v 12.8553 73.8732 -0.007972 +v 12.4881 73.8697 4.34047 +v 6.63864 76.0427 -0.297924 +v 6.73742 76.5658 4.06231 +v 0.17221 78.9819 -0.766734 +v 1.8004 79.4683 -0.216729 +v 5.03455 78.8748 4.59291 +v 2.6826 79.3323 6.2007 +v 6.75379 70.7195 -2.31767 +v 5.3431 70.3757 -5.91889 +v 2.75252 70.6518 -6.78095 +v 15.4878 69.7144 3.46285 +v 16.4828 71.2684 2.75554 +v 1.75119 66.6301 -4.90204 +v 3.41759 65.811 -4.85824 +v 4.93953 65.1074 -3.24588 +v 5.32987 65.9527 -0.014634 +v 12.9007 73.1722 0.062804 +v 12.6592 73.0147 3.71933 +v 16.3747 72.5152 0.554238 +v 16.0157 72.3028 4.64492 +v 19.5474 72.0284 0.547838 +v 19.0336 71.7416 5.11034 +v 16.1723 71.9212 -0.269817 +v 18.4447 70.9376 -1.39036 +v 15.432 71.6715 5.31036 +v 17.7215 70.3537 6.26215 +v 14.0653 72.9572 4.48276 +v 14.4938 73.0101 0.068066 +v 14.2562 70.2529 6.40722 +v 15.33 70.9056 -2.36181 +v 15.9035 68.1508 7.71889 +v 17.0802 69.5886 -3.22789 +v 16.7938 65.9537 9.66341 +v 18.2066 67.9785 -4.74797 +v 22.2463 71.2739 -0.064836 +v 19.1093 67.7687 8.40683 +v 20.1353 69.1695 -3.42308 +v 21.4869 70.6347 6.38541 +v 12.0882 71.4467 5.521 +v 2.81357 63.4025 1.94246 +v 4.50946 63.5634 0.58848 +v 4.52326 63.556 -3.5945 +v 15.2588 68.2947 1.83466 +v 15.6633 69.2484 -0.122036 +v 16.4259 71.0714 0.53204 +v 5.89822 60.8322 0.32173 +v 6.46948 60.269 -4.09688 +v 4.82134 58.7687 -5.7897 +v 4.46486 59.9088 3.1319 +v 2.21888 59.3982 4.24378 +v 2.30795 63.0356 -4.94981 +v 3.80104 54.3931 -6.47408 +v 3.35012 50.305 -6.90102 +v 4.74687 57.3048 5.58187 +v 5.47585 53.2441 7.30024 +v 5.99295 50.5803 7.98186 +v 4.09693 52.0215 -6.64897 +v 22.3832 71.7898 3.44688 +v 20.211 69.062 7.62833 +v 21.4198 70.4772 -2.07171 +v 3.43293 56.4175 -6.24327 +v 5.52547 59.6511 -4.94131 +v 4.54667 58.7215 4.57794 +v 2.59853 56.3564 6.34423 +v 2.75806 52.4465 7.99651 +v 2.8966 49.5192 8.53818 +v 10.4995 71.8205 -1.31098 +v 9.60696 71.8131 4.03 +v 9.70957 74.6658 4.68937 +v 6.98997 72.1468 4.36944 +v 13.2927 71.7102 -1.84832 +v 2.45339 81.3965 3.93635 +v 3.34147 80.506 1.55171 +v 2.98003 77.762 1.77544 +v 3.19204 75.5801 1.3266 +v 4.93023 77.3726 4.36818 +v 5.18786 77.2259 2.16219 +v -12.6592 73.0147 3.71933 +v -15.7114 71.5971 4.10859 +v -18.4715 71.1237 4.62582 +v -16.0789 71.7754 0.56202 +v -18.9411 71.4767 0.800779 +v 0.572154 54.8227 -6.6405 +v -6.25e-007 52.8775 -6.88806 +v 0 51.8751 8.23645 +v 0.000248 55.5302 6.67737 +v 8e-006 58.2993 4.9558 +v 0 56.9335 -6.28305 +v 2.5e-007 50.5279 -7.0935 +v -1.6867 58.9521 4.01574 +v -1.95055 56.0634 5.85507 +v -2.4034 52.3401 7.80716 +v -2e-006 60.0434 -1.30253 +v 15.7114 71.5971 4.10859 +v 18.4716 71.1228 4.62638 +v 16.0789 71.7754 0.56202 +v 18.9411 71.4769 0.801488 +v 1.6867 58.9521 4.01574 +v 1.95055 56.3488 5.85507 +v 2.4034 52.6264 7.80716 +v -5e-007 54.716 -6.9754 +v 2.28862 56.5916 -6.39891 +v -5e-007 51.6854 -7.2815 +v 2.31785 53.8042 -6.78247 +v 2.29446 54.9342 -6.64491 +v -1.5e-006 49.3897 -7.39594 +v 2.68702 49.6231 -7.05956 +v 2.54773 50.33 -7.00463 +v -1e-006 49.4075 -7.26866 +v 2.35523 52.6239 -6.84303 +v 2.48137 51.423 -6.91952 +v 4.0305 53.2536 -6.54868 +v 3.8436 55.4189 -6.34579 +v 2.31785 54.8091 -6.51586 +v 2.35523 53.8225 -6.61907 +v 4.36229 50.9607 -6.74289 +v 2.68702 50.3459 -6.92298 +v 2.48137 52.6429 -6.70763 +v 2.54773 51.4413 -6.79836 +v 2.28862 55.7467 -6.39088 +v -5e-007 53.8889 -6.79093 +v 0 51.7209 -6.97778 +v 3.07488 54.7905 -6.56253 +v 1.54913 52.7206 -6.97143 +v 1.67527 50.3719 -7.10514 +v 1.52574 55.3659 -6.68082 +v 3.2244 52.5278 -6.73106 +v 3.48983 50.2887 -6.91634 +v 1.54913 54.1896 -6.64438 +v 3.07488 55.4282 -6.37768 +v 1.67527 51.926 -6.82636 +v 3.2244 53.3591 -6.58886 +v 1.81456 49.6738 -7.09642 +v 3.48983 51.0115 -6.77976 +# 918 texture vertices +vt 0.785528 0.092731 +vt 0.797742 0.048858 +vt 0.937775 0.047635 +vt 0.008989 0.900353 +vt 0.107387 0.952254 +vt 0.109396 0.727182 +vt 0.007787 0.759061 +vt 0.656069 0.823426 +vt 0.599489 0.83193 +vt 0.616261 0.673035 +vt 0.654249 0.977476 +vt 0.580842 0.980553 +vt 0.662925 0.684252 +vt 0.732856 0.572286 +vt 0.697284 0.580353 +vt 0.735655 0.532984 +vt 0.006451 0.602213 +vt 0.671471 0.588199 +vt 0.623473 0.556584 +vt 0.628491 0.502281 +vt 0.512251 0.846874 +vt 0.399451 0.99684 +vt 0.496407 0.989032 +vt 0.406689 0.59707 +vt 0.40598 0.842193 +vt 0.244482 0.991588 +vt 0.283803 0.839501 +vt 0.499354 0.588602 +vt 0.408038 0.509541 +vt 0.302061 0.57712 +vt 0.124008 0.531667 +vt 0.618168 0.317018 +vt 0.622932 0.012425 +vt 0.520587 0.019957 +vt 0.496979 0.305195 +vt 0.618168 0.339776 +vt 0.741172 0.396787 +vt 0.494986 0.505565 +vt 0.738562 0.013113 +vt 0.741172 0.375293 +vt 0.410094 0.019027 +vt 0.303323 0.019918 +vt 0.407709 0.308125 +vt 0.133678 0.01729 +vt 0.019056 0.017751 +vt 0.009087 0.372005 +vt 0.127601 0.343801 +vt 0.291987 0.316997 +vt 0.30519 0.46924 +vt 0.125156 0.50049 +vt 0.407714 0.461498 +vt 0.495098 0.474799 +vt 0.628491 0.488373 +vt 0.495098 0.462155 +vt 0.006042 0.532652 +vt 0.006042 0.522537 +vt 0.735655 0.512755 +vt 0.009087 0.388442 +vt 0.127601 0.358973 +vt 0.407714 0.44759 +vt 0.30519 0.454702 +vt 0.125156 0.487846 +vt 0.496979 0.326689 +vt 0.407709 0.325826 +vt 0.291987 0.335962 +vt 0.495803 0.411366 +vt 0.546822 0.410721 +vt 0.623545 0.417177 +vt 0.686112 0.44154 +vt 0.738598 0.4509 +vt 0.0801018 0.449261 +vt 0.125894 0.448952 +vt 0.255605 0.427973 +vt 0.301881 0.424942 +vt 0.375239 0.416266 +vt 0.407713 0.411681 +vt 0.436755 0.408257 +vt 0.0800252 0.449195 +vt 0.0076673 0.450963 +vt 0.255443 0.427886 +vt 0.436684 0.408353 +vt 0.546731 0.410812 +vt 0.495802 0.411477 +vt 0.928484 0.351396 +vt 0.90516 0.386306 +vt 0.915839 0.604076 +vt 0.752968 0.346298 +vt 0.773032 0.388924 +vt 0.837109 0.371883 +vt 0.812982 0.052651 +vt 0.855298 0.038013 +vt 0.79999 0.123439 +vt 0.976555 0.791911 +vt 0.932893 0.80233 +vt 0.960391 0.874843 +vt 0.933663 0.199099 +vt 0.952642 0.23236 +vt 0.86014 0.232647 +vt 0.855503 0.200099 +vt 0.707142 0.784131 +vt 0.750697 0.80026 +vt 0.712363 0.761663 +vt 0.783196 0.201078 +vt 0.786528 0.19428 +vt 0.835259 0.232739 +vt 0.772784 0.230492 +vt 0.981246 0.971667 +vt 0.953683 0.947273 +vt 0.841295 0.959688 +vt 0.938249 0.263511 +vt 0.951352 0.232896 +vt 0.952489 0.232691 +vt 0.854647 0.273054 +vt 0.699462 0.975017 +vt 0.72335 0.887919 +vt 0.718292 0.889122 +vt 0.733158 0.943235 +vt 0.838051 0.335813 +vt 0.744536 0.588837 +vt 0.767375 0.596141 +vt 0.804603 0.602567 +vt 0.840623 0.794912 +vt 0.91294 0.752449 +vt 0.905993 0.762765 +vt 0.971334 0.765705 +vt 0.721206 0.875827 +vt 0.840063 0.886263 +vt 0.776119 0.762222 +vt 0.767254 0.749882 +vt 0.743461 0.772379 +vt 0.683649 0.865354 +vt 0.686282 0.867395 +vt 0.996103 0.881377 +vt 0.995656 0.88136 +vt 0.842663 0.994513 +vt 0.840483 0.911272 +vt 0.813134 0.900614 +vt 0.900024 0.049904 +vt 0.912522 0.123433 +vt 0.77986 0.264814 +vt 0.771906 0.232973 +vt 0.859912 0.234327 +vt 0.83959 0.586233 +vt 0.87492 0.598934 +vt 0.869853 0.902259 +vt 0.996262 0.880408 +vt 0.681668 0.872204 +vt 0.695163 0.873441 +vt 0.941928 0.590639 +vt 0.92561 0.193426 +vt 0.934865 0.770607 +vt 0.839188 0.602065 +vt 0.866839 0.614024 +vt 0.811785 0.614259 +vt 0.683678 0.865254 +vt 0.995593 0.881458 +vt 0.996086 0.881477 +vt 0.695387 0.873461 +vt 0.718321 0.888986 +vt 0.958801 0.892008 +vt 0.723327 0.887789 +vt 0.951221 0.23295 +vt 0.813257 0.900549 +vt 0.8358 0.232737 +vt 0.9944 0.519083 +vt 0.987217 0.186962 +vt 0.992682 0.19325 +vt 0.975809 0.501666 +vt 0.99583 0.518703 +vt 0.958002 0.518703 +vt 0.969756 0.191476 +vt 0.974968 0.185263 +vt 0.974624 0.004073 +vt 0.991959 0.056129 +vt 0.974624 0.055936 +vt 0.956572 0.519083 +vt 0.968286 0.193471 +vt 0.957051 0.193576 +vt 0.990529 0.056509 +vt 0.973194 0.004453 +vt 0.957253 0.055895 +vt 0.958684 0.055515 +vt 0.987446 0.180629 +vt 0.992649 0.187046 +vt 0.969967 0.185589 +vt 0.97495 0.178685 +vt 0.967938 0.18913 +vt 0.957056 0.189819 +vt 0.986316 0.211798 +vt 0.992813 0.218078 +vt 0.968767 0.219002 +vt 0.975039 0.211972 +vt 0.970416 0.220029 +vt 0.95701 0.220905 +vt 0.957042 0.199658 +vt 0.968711 0.198764 +vt 0.992698 0.196297 +vt 0.987062 0.191236 +vt 0.974986 0.192042 +vt 0.969524 0.197911 +vt 0.958472 0.199278 +vt 0.956984 0.238603 +vt 0.97177 0.23691 +vt 0.992895 0.233619 +vt 0.985781 0.226567 +vt 0.975079 0.226911 +vt 0.968174 0.235517 +vt 0.958415 0.238223 +vt 0.957058 0.18876 +vt 0.967856 0.188103 +vt 0.992644 0.186098 +vt 0.987454 0.180415 +vt 0.974953 0.17955 +vt 0.969961 0.185744 +vt 0.958488 0.18838 +vt 0.923308 0.008378 +vt 0.783275 0.0096 +vt 0.925561 0.091509 +vt 0.958441 0.220525 +vt 0.958487 0.189439 +vt 0.958481 0.193197 +vt 0 0 +vt 0.211563 0.874345 +vt 0.013559 0.811452 +vt 0.215377 0.822704 +vt 0.440258 0.889204 +vt 0.212109 0.930598 +vt 0.44738 0.815958 +vt 0.633202 0.862329 +vt 0.618626 0.921215 +vt 0.431144 0.921779 +vt 0.644868 0.741977 +vt 0.796949 0.721985 +vt 0.801364 0.82082 +vt 0.796019 0.924987 +vt 0.989127 0.720422 +vt 0.988057 0.817064 +vt 0.987693 0.930068 +vt 0.220547 0.76008 +vt 0.013196 0.926327 +vt 0.024829 0.716681 +vt 0.321618 0.314237 +vt 0.418916 0.315784 +vt 0.446952 0.748107 +vt 0.597208 0.316004 +vt 0.71298 0.318828 +vt 0.876902 0.321282 +vt 0.19946 0.313008 +vt 0.42182 0.305781 +vt 0.309805 0.306069 +vt 0.415993 0.168882 +vt 0.548438 0.301904 +vt 0.518364 0.162262 +vt 0.737751 0.166071 +vt 0.69546 0.300113 +vt 0.815812 0.193313 +vt 0.790517 0.303053 +vt 0.900358 0.227079 +vt 0.972522 0.237776 +vt 0.096185 0.313346 +vt 0.201689 0.303812 +vt 0.174021 0.172026 +vt 0.528062 0.08797 +vt 0.735612 0.096413 +vt 0.830029 0.108098 +vt 0.142403 0.135843 +vt 0.108622 0.141054 +vt 0.415856 0.089597 +vt 0.867449 0.309418 +vt 0.03642 0.207693 +vt 0.103657 0.183559 +vt 0.176071 0.08861 +vt 0.848441 0.181272 +vt 0.933552 0.163921 +vt 0.993187 0.165288 +vt 0.00715 0.140666 +vt 0.035198 0.135729 +vt 0.060286 0.131605 +vt 0.88184 0.149495 +vt 0.95539 0.138624 +vt 0.420041 0.013099 +vt 0.540067 0.035567 +vt 0.719769 0.035501 +vt 0.822666 0.010544 +vt 0.200001 0.013273 +vt 0.020995 0.981463 +vt 0.981894 0.988945 +vt 0.806918 0.98866 +vt 0.211607 0.98542 +vt 0.613773 0.98686 +vt 0.427508 0.985357 +vt 0.08551 0.115611 +vt 0.035657 0.078819 +vt 0.085319 0.07879 +vt 0.054166 0.027248 +vt 0.134426 0.077908 +vt 0.115361 0.027008 +vt 0.765444 0.76513 +vt 0.891887 0.72352 +vt 0.762261 0.691124 +vt 0.623914 0.720368 +vt 0.636873 0.84107 +vt 0.762923 0.853191 +vt 0.621545 0.617767 +vt 0.5094 0.730588 +vt 0.573576 0.857614 +vt 0.50168 0.631136 +vt 0.364123 0.641381 +vt 0.357442 0.734593 +vt 0.353549 0.799011 +vt 0.357921 0.696092 +vt 0.486046 0.851047 +vt 0.188583 0.700344 +vt 0.206114 0.603246 +vt 0.095136 0.604135 +vt 0.077055 0.692895 +vt 0.122052 0.832742 +vt 0.886889 0.845445 +vt 0.036785 0.829511 +vt 0.744512 0.339079 +vt 0.611428 0.336334 +vt 0.621198 0.512277 +vt 0.756108 0.512839 +vt 0.105383 0.333255 +vt 0.237773 0.314776 +vt 0.075563 0.296457 +vt 0.468589 0.339592 +vt 0.739612 0.310456 +vt 0.885176 0.321741 +vt 0.924701 0.28124 +vt 0.597214 0.310492 +vt 0.865684 0.23641 +vt 0.774226 0.221368 +vt 0.631956 0.195064 +vt 0.521748 0.198368 +vt 0.383731 0.339196 +vt 0.479953 0.511031 +vt 0.518161 0.308958 +vt 0.275101 0.339989 +vt 0.239356 0.491436 +vt 0.431715 0.310015 +vt 0.267824 0.242423 +vt 0.151125 0.25567 +vt 0.403027 0.197439 +vt 0.16269 0.334695 +vt 0.860269 0.34564 +vt 0.869133 0.513878 +vt 0.881226 0.618598 +vt 0.759194 0.60964 +vt 0.366304 0.510425 +vt 0.120443 0.479857 +vt 0.220395 0.846201 +vt 0.34863 0.849252 +vt 0.975759 0.035914 +vt 0.944848 0.036418 +vt 0.926406 0.16527 +vt 0.973657 0.166836 +vt 0.034236 0.054101 +vt 0.0451 0.175013 +vt 0.098631 0.169224 +vt 0.058361 0.616223 +vt 0.050302 0.628903 +vt 0.045121 0.61443 +vt 0.911372 0.036174 +vt 0.846092 0.147703 +vt 0.059548 0.60249 +vt 0.045913 0.600404 +vt 0.067608 0.572022 +vt 0.102496 0.048099 +vt 0.068901 0.051054 +vt 0.169191 0.155896 +vt 0.659075 0.124377 +vt 0.814126 0.118022 +vt 0.621634 0.046239 +vt 0.529292 0.046682 +vt 0.52549 0.123212 +vt 0.795254 0.179526 +vt 0.37785 0.12488 +vt 0.417209 0.046896 +vt 0.217715 0.124644 +vt 0.241419 0.192807 +vt 0.320123 0.042499 +vt 0.02041 0.4557 +vt 0.039956 0.339719 +vt 0.080184 0.34878 +vt 0.104807 0.46827 +vt 0.023517 0.494847 +vt 0.08876 0.502299 +vt 0.084971 0.52866 +vt 0.016684 0.523769 +vt 0.033861 0.569234 +vt 0.953983 0.241509 +vt 0.05663 0.254256 +vt 0.707881 0.042783 +vt 0.619878 0.008164 +vt 0.685211 0.009392 +vt 0.176165 0.929755 +vt 0.922829 0.944343 +vt 0.62384 0.941911 +vt 0.341948 0.936021 +vt 0.50476 0.940239 +vt 0.764956 0.946428 +vt 0.191897 0.991068 +vt 0.334271 0.992996 +vt 0.888808 0.343125 +vt 0.94694 0.309698 +vt 0.899418 0.35629 +vt 0.641768 0.988054 +vt 0.769916 0.995478 +vt 0.937743 0.582776 +vt 0.892387 0.506023 +vt 0.897847 0.482646 +vt 0.489379 0.993951 +vt 0.941101 0.415843 +vt 0.911199 0.989051 +vt 0.992886 0.353259 +vt 0.98226 0.367204 +vt 0.990128 0.495765 +vt 0.982445 0.484338 +vt 0.97628 0.415859 +vt 0.0148 0.949176 +vt 0.906066 0.419846 +vt 0.01439 0.427971 +vt 0.014523 0.535814 +vt 0.028198 0.428265 +vt 0.770362 0.614635 +vt 0.730473 0.754829 +vt 0.875418 0.623282 +vt 0.789076 0.457471 +vt 0.633223 0.443458 +vt 0.670895 0.599491 +vt 0.646207 0.702924 +vt 0.82 0.813879 +vt 0.540321 0.795508 +vt 0.636905 0.861604 +vt 0.745419 0.928117 +vt 0.97877 0.238301 +vt 0.976118 0.184819 +vt 0.762872 0.179246 +vt 0.176594 0.726002 +vt 0.137312 0.834031 +vt 0.262492 0.883359 +vt 0.288663 0.789256 +vt 0.964887 0.141907 +vt 0.958323 0.07742 +vt 0.356316 0.985809 +vt 0.514918 0.990944 +vt 0.359055 0.965605 +vt 0.234531 0.952148 +vt 0.382668 0.829796 +vt 0.540647 0.858251 +vt 0.38717 0.74286 +vt 0.288078 0.708309 +vt 0.364308 0.926853 +vt 0.524397 0.928409 +vt 0.50419 0.577992 +vt 0.585272 0.587478 +vt 0.420864 0.426654 +vt 0.322914 0.438289 +vt 0.549249 0.665234 +vt 0.42145 0.629412 +vt 0.305774 0.602643 +vt 0.199416 0.660944 +vt 0.189075 0.579485 +vt 0.038591 0.624804 +vt 0.06037 0.553865 +vt 0.098892 0.906286 +vt 0.234472 0.952292 +vt 0.805128 0.966301 +vt 0.388522 0.564218 +vt 0.901343 0.855254 +vt 0.107963 0.20351 +vt 0.09549 0.28108 +vt 0.138099 0.284131 +vt 0.961424 0.623565 +vt 0.885521 0.452084 +vt 0.285508 0.53341 +vt 0.184274 0.524438 +vt 0.242794 0.44116 +vt 0.663693 0.304434 +vt 0.495329 0.430964 +vt 0.532291 0.3034 +vt 0.327739 0.310383 +vt 0.425053 0.306134 +vt 0.980366 0.258784 +vt 0.486561 0.166414 +vt 0.826079 0.327238 +vt 0.334178 0.178779 +vt 0.235684 0.180082 +vt 0.247465 0.311904 +vt 0.150817 0.043106 +vt 0.172456 0.178069 +vt 0.207233 0.074215 +vt 0.192529 0.019432 +vt 0.652735 0.148345 +vt 0.535949 0.046865 +vt 0.804234 0.24725 +vt 0.417793 0.075246 +vt 0.28879 0.105335 +vt 0.218385 0.284912 +vt 0.180694 0.283347 +vt 0.074868 0.353152 +vt 0.261684 0.358281 +vt 0.210426 0.355653 +vt 0.313171 0.443204 +vt 0.074246 0.435663 +vt 0.149628 0.356701 +vt 0.163948 0.435309 +vt 0.069839 0.510071 +vt 0.298572 0.068978 +vt 0.258812 0.050151 +vt 0.429438 0.009774 +vt 0.329377 0.008229 +vt 0.972992 0.43418 +vt 0.047162 0.877513 +vt 0.100448 0.690643 +vt 0.147236 0.606993 +vt 0.011617 0.857743 +vt 0.064842 0.781996 +vt 0.016979 0.745441 +vt 0.046278 0.663831 +vt 0.103185 0.631338 +vt 0.136796 0.077544 +vt 0.074831 0.03337 +vt 0.073596 0.083319 +vt 0.074075 0.034512 +vt 0.136927 0.07695 +vt 0.075927 0.083142 +vt 0.014173 0.074012 +vt 0.014303 0.073418 +vt 0.075363 0.186565 +vt 0.075247 0.185415 +vt 0.750557 0.007235 +vt 0.861687 0.09054 +vt 0.751714 0.071227 +vt 0.629633 0.091453 +vt 0.748576 0.130964 +vt 0.0281 0.221114 +vt 0.01473 0.220826 +vt 0.027804 0.536096 +vt 0.014673 0.608761 +vt 0.028212 0.608028 +vt 0.499533 0.569547 +vt 0.501072 0.704532 +vt 0.531609 0.662717 +vt 0.501091 0.47957 +vt 0.475473 0.577455 +vt 0.467263 0.668329 +vt 0.523399 0.577455 +vt 0.531082 0.450768 +vt 0.501189 0.415699 +vt 0.471116 0.450768 +vt 0.501399 0.389483 +vt 0.500409 0.852509 +vt 0.500381 0.989593 +vt 0.555217 0.977588 +vt 0.420262 0.746938 +vt 0.409015 0.87622 +vt 0.446986 0.977588 +vt 0.581941 0.746938 +vt 0.500246 0.337932 +vt 0.547387 0.324249 +vt 0.500004 0.325839 +vt 0.454815 0.324249 +vt 0.501239 0.227331 +vt 0.500075 0.289292 +vt 0.550104 0.301582 +vt 0.501194 0.195798 +vt 0.446298 0.239217 +vt 0.452098 0.301582 +vt 0.555904 0.239217 +vt 0.578038 0.201916 +vt 0.501207 0.13824 +vt 0.424165 0.201916 +vt 0.991351 0.448262 +vt 0.983308 0.229065 +vt 0.915733 0.25721 +vt 0.010851 0.448262 +vt 0.080829 0.478692 +vt 0.086469 0.25721 +vt 0.978911 0.019992 +vt 0.898086 0.018465 +vt 0.018894 0.229065 +vt 0.104116 0.018465 +vt 0.023291 0.019992 +vt 0.618501 0.167744 +vt 0.501452 0.017889 +vt 0.383702 0.167744 +vt 0.618259 0.021686 +vt 0.500383 0.316033 +vt 0.553131 0.576971 +vt 0.565892 0.63518 +vt 0.582346 0.558458 +vt 0.591028 0.666837 +vt 0.629137 0.772562 +vt 0.616253 0.660016 +vt 0.612087 0.561042 +vt 0.593188 0.87622 +vt 0.658163 0.673843 +vt 0.630129 0.635937 +vt 0.61015 0.965237 +vt 0.631364 0.596575 +vt 0.679404 0.869611 +vt 0.748698 0.573999 +vt 0.668602 0.587196 +vt 0.621466 0.454018 +vt 0.670281 0.471395 +vt 0.573742 0.453138 +vt 0.542689 0.36254 +vt 0.55657 0.360182 +vt 0.613176 0.349912 +vt 0.733044 0.416267 +vt 0.662082 0.377009 +vt 0.603735 0.261835 +vt 0.656718 0.294073 +vt 0.760861 0.497723 +vt 0.843089 0.661995 +vt 0.854884 0.758625 +vt 0.880974 0.750966 +vt 0.643716 0.233025 +vt 0.851325 0.580773 +vt 0.907147 0.604772 +vt 0.800765 0.358051 +vt 0.772218 0.426651 +vt 0.804596 0.018242 +vt 0.886315 0.537973 +vt 0.803526 0.600839 +vt 0.9714 0.59136 +vt 0.9326 0.528569 +vt 0.957769 0.699493 +vt 0.926667 0.470181 +vt 0.920579 0.718323 +vt 0.459513 0.36254 +vt 0.89793 0.859525 +vt 0.926371 0.832137 +vt 0.866859 0.789665 +vt 0.917921 0.992344 +vt 0.882832 0.88494 +vt 0.947728 0.828005 +vt 0.972277 0.831021 +vt 0.990304 0.652487 +vt 0.441381 0.576902 +vt 0.430482 0.637323 +vt 0.417668 0.451699 +vt 0.412443 0.560654 +vt 0.409822 0.667135 +vt 0.382917 0.660303 +vt 0.367454 0.76508 +vt 0.382096 0.567044 +vt 0.368632 0.636706 +vt 0.340299 0.653267 +vt 0.322798 0.869611 +vt 0.392053 0.965237 +vt 0.364174 0.58892 +vt 0.333601 0.587196 +vt 0.25444 0.568387 +vt 0.378578 0.454018 +vt 0.331202 0.478589 +vt 0.445633 0.360182 +vt 0.389027 0.349912 +vt 0.340121 0.377009 +vt 0.266208 0.416267 +vt 0.398468 0.261835 +vt 0.345484 0.294073 +vt 0.226845 0.510069 +vt 0.199845 0.580569 +vt 0.358486 0.233025 +vt 0.201438 0.358051 +vt 0.383943 0.021686 +vt 0.213788 0.434859 +vt 0.197607 0.018242 +vt 0.627209 0.912143 +vt 0.566764 0.904245 +vt 0.62732 0.99449 +vt 0.0936311 0.020487 +vt 0.11644 0.114966 +vt 0.184561 0.024933 +vt 0.770709 0.970315 +vt 0.871914 0.985126 +vt 0.881544 0.881599 +vt 0.164806 0.177175 +vt 0.249068 0.083664 +vt 0.993909 0.996536 +vt 0.993909 0.840592 +vt 0.25077 0.203666 +vt 0.317371 0.14586 +vt 0.259595 0.022071 +vt 0.309533 0.079779 +vt 0.670786 0.95013 +vt 0.707539 0.898006 +vt 0.518797 0.784841 +vt 0.566071 0.829154 +vt 0.629818 0.782355 +vt 0.541811 0.690209 +vt 0.480391 0.665388 +vt 0.470637 0.756163 +vt 0.533324 0.821555 +vt 0.614072 0.890628 +vt 0.345169 0.087357 +vt 0.621039 0.840253 +vt 0.364461 0.016298 +vt 0.397317 0.847692 +vt 0.450629 0.860058 +vt 0.4068 0.738224 +vt 0.39598 0.920099 +vt 0.993909 0.701052 +vt 0.877656 0.671909 +vt 0.842637 0.842787 +vt 0.993909 0.504804 +vt 0.893858 0.506437 +vt 0.993909 0.778968 +vt 0.406967 0.541655 +vt 0.412468 0.581716 +vt 0.482262 0.519524 +vt 0.464563 0.479825 +vt 0.406967 0.395646 +vt 0.42465 0.669559 +vt 0.494609 0.553516 +vt 0.414826 0.639634 +vt 0.502752 0.607414 +vt 0.99247 0.411615 +vt 0.406967 0.241279 +vt 0.476533 0.40691 +vt 0.541655 0.301671 +vt 0.54683 0.247757 +vt 0.453588 0.209002 +vt 0.476899 0.244518 +vt 0.406967 0.189624 +vt 0.99247 0.272096 +vt 0.993909 0.174101 +vt 0.929845 0.295969 +vt 0.879856 0.413607 +vt 0.406967 0.137969 +vt 0.476899 0.192863 +vt 0.455224 0.132815 +vt 0.479352 0.165408 +vt 0.406967 0.102798 +vt 0.501845 0.192858 +vt 0.406967 0.006718 +vt 0.406967 0.037173 +vt 0.553456 0.126934 +vt 0.506163 0.0718143 +vt 0.480212 0.066826 +vt 0.482516 0.0442545 +vt 0.18204 0.412724 +vt 0.203158 0.492607 +vt 0.198304 0.413008 +vt 0.99247 0.09754 +vt 0.924069 0.200629 +vt 0.99247 0.011419 +vt 0.918519 0.114398 +vt 0.918255 0.033587 +vt 0.388285 0.386922 +vt 0.345245 0.378811 +vt 0.388285 0.35282 +vt 0.406967 0.067628 +vt 0.551737 0.192847 +vt 0.479352 0.130238 +vt 0.42736 0.94008 +vt 0.496535 0.971282 +vt 0.510542 0.884634 +vt 0.358424 0.545584 +vt 0.239355 0.626026 +vt 0.249397 0.534148 +vt 0.343648 0.630061 +vt 0.267763 0.632464 +vt 0.768291 0.692576 +vt 0.782361 0.654564 +vt 0.616765 0.506276 +vt 0.540242 0.493979 +vt 0.638037 0.553905 +vt 0.727008 0.579477 +vt 0.793341 0.507758 +vt 0.695844 0.463879 +vt 0.708144 0.80948 +vt 0.601069 0.462755 +vt 0.252096 0.510727 +vt 0.715092 0.853082 +vt 0.601858 0.712104 +vt 0.138962 0.502306 +vt 0.564364 0.540995 +vt 0.57722 0.591646 +vt 0.0328071 0.538851 +vt 0.146808 0.533741 +vt 0.637216 0.595564 +vt 0.782346 0.427775 +vt 0.560471 0.174244 +vt 0.568999 0.095874 +vt 0.630759 0.112138 +vt 0.62137 0.171381 +vt 0.590049 0.226294 +vt 0.669824 0.118515 +vt 0.80135 0.179958 +vt 0.663994 0.233795 +vt 0.0449671 0.627066 +vt 0.155301 0.625064 +vt 0.0459041 0.70103 +vt 0.662989 0.08977 +vt 0.236166 0.726212 +vt 0.653164 0.270776 +vt 0.588682 0.246695 +vt 0.338388 0.730808 +vt 0.148215 0.72643 +vt 0.710915 0.066675 +vt 0.0410881 0.746607 +vt 0.142154 0.778723 +vt 0.238218 0.778427 +vt 0.798605 0.237044 +vt 0.797343 0.277138 +vt 0.711885 0.293764 +vt 0.520783 0.460601 +vt 0.592102 0.420447 +vt 0.720194 0.026718 +vt 0.806635 0.085552 +vt 0.805031 0.127275 +vt 0.293242 0.283685 +vt 0.292665 0.252069 +vt 0.266818 0.251308 +vt 0.17842 0.244027 +vt 0.175241 0.287055 +vt 0.809328 0.050986 +vt 0.135657 0.8335 +vt 0.247219 0.833113 +vt 0.124128 0.92656 +vt 0.114196 0.835217 +vt 0.289402 0.822637 +vt 0.318522 0.877731 +vt 0.257849 0.926081 +vt 0.193488 0.999186 +vt 0.100035 0.989999 +vt 0.0508841 0.965601 +vt 0.287905 0.991169 +vt 0.338647 0.954971 +vt 0.0661201 0.886994 +vt 0.0240831 0.828005 +vt 0.0168901 0.927022 +vt 0.353018 0.788278 +vt 0.37194 0.830371 +vt 0.388151 0.868043 +vt 0.366411 0.918733 +vt 0.0376421 0.787615 +vt 0.179454 0.401693 +vt 0.251873 0.392792 +vt 0.292383 0.360225 +vt 0.175056 0.360429 +vt 0.129114 0.207518 +vt 0.129858 0.439378 +vt 0.104973 0.362288 +vt 0.00612211 0.867378 +vt 0.0857601 0.164855 +vt 0.106178 0.287878 +vt 0.0859121 0.482133 +vt 0.0407731 0.197149 +vt 0.00477311 0.272383 +vt 0.00223711 0.328279 +vt 0.0430311 0.449263 +vt 0.0152291 0.2308 +vt 0.00938811 0.380986 +vt 0.0193311 0.413668 +vt 0.294409 0.403196 +vt 0.765751 0.36891 +vt 0.645078 0.346658 +vt 0.570272 0.334258 +vt 0.85091 0.339445 +vt 0.296305 0.181695 +vt 0.319499 0.227635 +vt 0.388285 0.156227 +vt 0.353368 0.516955 +vt 0.390959 0.531565 +vt 0.384636 0.415088 +vt 0.324795 0.489783 +vt 0.33878 0.501422 +vt 0.866954 0.283639 +vt 0.324573 0.257772 +vt 0.360992 0.241874 +vt 0.269739 0.481973 +vt 0.298887 0.48538 +vt 0.276366 0.414371 +vt 0.26148 0.414111 +vt 0.558065 0.081791 +vt 0.237647 0.485 +vt 0.214567 0.413292 +vt 0.856039 0.232817 +vt 0.321614 0.27934 +vt 0.310848 0.337727 +vt 0.359467 0.288467 +vt 0.83582 0.152886 +vt 0.303208 0.37089 +vt 0.352777 0.345899 +vt 0.825373 0.096035 +vt 0.246594 0.413851 +vt 0.230581 0.413572 +vt 0.309648 0.414952 +vt 0.557704 0.986199 +vt 0.549284 0.220302 +vt 0.251327 0.460275 +vt 0.258167 0.447912 +vt 0.253693 0.483487 +vt 0.555761 0.104363 +vt 0.242121 0.449425 +vt 0.287627 0.449876 +vt 0.388285 0.30172 +vt 0.388285 0.257111 +vt 0.455797 0.0670933 +vt 0.192599 0.452666 +vt 0.199922 0.439541 +vt 0.480212 0.097281 +vt 0.208863 0.452949 +vt 0.504053 0.129136 +vt 0.552597 0.159891 +vt 0.284313 0.483676 +vt 0.273053 0.448172 +vt 0.281664 0.460575 +vt 0.264233 0.436732 +vt 0.220403 0.488804 +vt 0.218457 0.463633 +vt 0.226107 0.449146 +vt 0.232936 0.437381 +# 1333 normals +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.351061 0.612018 -0.708654 +vn -0.333971 0.00328916 -0.942578 +vn -0.233089 -0.165544 -0.958261 +vn 3.11506e-005 -0.473442 -0.880825 +vn 0.0314178 0.311483 0.949732 +vn 0.0402569 0.449245 0.892501 +vn -0.178309 -0.0746577 0.981138 +vn -0.0153662 0.778183 0.62785 +vn -0.223286 0.854167 0.469619 +vn -0.0992713 0.47927 0.872035 +vn -0.0297101 0.438965 0.898013 +vn 0.0162224 0.41024 0.911833 +vn 0.318775 -0.108516 0.941598 +vn 0.49916 0.0671001 0.863908 +vn 0.136365 -0.141408 0.980514 +vn -0.124419 -0.831788 -0.54097 +vn 0.0225389 -0.985951 0.165505 +vn -0.750085 0.0860174 -0.655724 +vn 0.144263 -0.146127 -0.978691 +vn 0.130907 -0.592754 0.794673 +vn -0.158101 -0.659788 0.734632 +vn -0.283537 -0.0906059 0.954671 +vn 0.734143 -0.107844 -0.670376 +vn 0.476287 -0.878171 -0.0443444 +vn 0.57195 -0.1995 0.795659 +vn -0.17583 -0.967152 0.18358 +vn 0.0594301 -0.625756 0.777752 +vn -0.570832 0.410198 0.711258 +vn -0.823912 0.462764 0.327138 +vn -0.360633 0.609147 0.706317 +vn -0.843809 0.363826 0.394482 +vn -0.863431 0.439987 0.246776 +vn -0.812169 0.329088 -0.48175 +vn -0.860429 0.39672 -0.319804 +vn -0.416681 0.0585036 0.907168 +vn -0.855161 0.18501 0.484223 +vn -0.789152 0.120726 -0.602216 +vn 0.080104 -0.10921 -0.990786 +vn -0.110921 -0.65231 -0.749792 +vn 0.622837 -0.534287 0.5715 +vn 0.8355 -0.146198 0.529684 +vn -0.164931 -0.073086 0.983593 +vn 0.0221266 -0.632363 0.774356 +vn 0.511675 -0.499901 0.698776 +vn 0.849934 -0.478225 -0.221162 +vn -0.294095 -0.164591 0.941498 +vn 0.422092 -0.301489 0.854952 +vn 0.91158 -0.271821 -0.308439 +vn 0.748236 -0.548586 -0.373089 +vn -0.865318 -0.120026 0.486639 +vn -0.969157 -0.200383 -0.143461 +vn -0.734857 -0.419954 0.532564 +vn 0.0177075 -0.286604 -0.957886 +vn -0.016553 -0.589855 -0.807339 +vn -0.762728 -0.528654 -0.372521 +vn -0.7651 0.513005 -0.389164 +vn -0.0011383 0.310047 -0.95072 +vn -0.761542 0.425922 0.488512 +vn -0.265935 0.490375 0.829946 +vn 0.730078 0.302151 0.612936 +vn -0.13058 0.343324 0.930095 +vn 0.80317 0.440333 -0.401278 +vn 0.102633 -0.477788 -0.872459 +vn -0.821732 0.301065 0.483856 +vn -0.733536 0.353259 -0.580631 +vn 0.134107 0.269433 -0.953636 +vn -0.304688 -0.411551 0.858948 +vn -0.840718 -0.357201 0.40694 +vn -0.756595 -0.461639 -0.463092 +vn -0.0261304 -0.0370894 0.99897 +vn 0.295619 -0.154798 0.942681 +vn 0.77259 -0.244251 0.586043 +vn 0.977467 -0.101804 0.184918 +vn 0.824942 -0.102558 -0.555835 +vn 0.463234 -0.153888 -0.872773 +vn -0.0441719 -0.154429 -0.987016 +vn -0.39169 -0.17249 -0.903784 +vn -0.944276 -0.124923 -0.304526 +vn -0.982409 -0.0193953 0.185733 +vn -0.796797 0.0025107 0.604242 +vn -0.586349 0.00260788 0.810054 +vn 0.570853 0.41015 0.711269 +vn 0.843799 0.363801 0.394528 +vn 0.423747 -0.149346 0.893383 +vn 0.0290481 0.886902 0.461044 +vn 0.405402 0.89149 0.202226 +vn 0.863426 0.439973 0.246817 +vn 0.441638 0.770947 -0.458907 +vn 0.0719003 0.426756 -0.901504 +vn 0.860425 0.396754 -0.319775 +vn 0.759591 0.307252 -0.573252 +vn 0.85766 -0.0405039 0.512619 +vn -0.127386 0.249435 -0.959976 +vn -0.657477 -0.540314 0.525152 +vn -0.835529 -0.146211 0.529635 +vn -0.748166 -0.548543 -0.373293 +vn -0.78185 -0.479666 -0.398285 +vn 0.301218 -0.449961 0.840716 +vn -0.911553 -0.271828 -0.308512 +vn -0.017702 -0.286583 -0.957892 +vn 0.170826 -0.126261 0.977178 +vn 0.865374 -0.120045 0.486535 +vn 0.837194 -0.167498 0.520625 +vn 0.969139 -0.200385 -0.143583 +vn 0.762649 -0.528597 -0.372763 +vn 0.0165756 -0.589691 -0.807459 +vn 0.0838607 0.201264 0.975941 +vn -0.0632465 0.595493 -0.800867 +vn 0.746973 0.549544 -0.37421 +vn 0.786167 0.322976 0.526904 +vn 0.341813 0.473428 0.811807 +vn 0.0645186 0.22301 0.972679 +vn -0.862769 0.180098 0.472434 +vn 0.0388691 -0.482811 -0.874862 +vn 0.76285 0.303168 0.571095 +vn 0.855818 0.371619 -0.359825 +vn -0.0255883 0.313465 -0.949255 +vn -0.704531 -0.272923 0.655094 +vn 0.241041 0.180566 0.95357 +vn 0.770722 -0.354616 0.529372 +vn -0.672571 0.526093 -0.520457 +vn 0.86486 -0.426352 -0.265031 +vn -0.962323 -0.188333 0.196125 +vn -0.575026 -0.393503 0.717287 +vn -0.135784 -0.167173 -0.976533 +vn -0.492703 0.0204663 -0.869957 +vn -0.954835 -0.00407803 -0.297107 +vn 0.799454 -0.170679 -0.575971 +vn 0.384512 -0.154471 -0.910104 +vn 0.883493 -0.00356182 0.468431 +vn 0.982128 -0.0218063 0.186948 +vn 0.584214 0.00630552 0.811575 +vn -0.316106 -0.120443 0.941048 +vn 0.240172 -0.0264779 0.970369 +vn 0.683055 -0.383224 -0.621752 +vn 0.873041 -0.444895 -0.199669 +vn 0.900389 -0.233541 -0.367094 +vn 0.189457 -0.583916 0.789397 +vn 0.485011 -0.304034 0.819956 +vn 0.833517 -0.486546 0.261769 +vn -0.38027 -0.836386 -0.394782 +vn -0.958251 0.0363649 0.283605 +vn -0.244696 -0.580782 -0.776412 +vn 0.791098 -0.373029 -0.484782 +vn 0.903184 -0.0765685 -0.42237 +vn -0.442826 0.425649 -0.789131 +vn -0.875365 0.149467 -0.459777 +vn -0.874796 -0.0704385 -0.479344 +vn -0.896282 -0.316855 -0.310293 +vn 0.179713 -0.203626 0.962413 +vn -0.422822 -0.345078 0.837939 +vn -0.664592 0.309367 -0.680154 +vn -0.663088 -0.368764 0.651404 +vn 0.0716093 0.981328 -0.178514 +vn 0.934867 0.173739 -0.309578 +vn 0.764328 0.600413 0.235176 +vn -0.897924 0.435945 -0.0606951 +vn 0.384907 0.323088 -0.864558 +vn -0.392676 0.89268 -0.221196 +vn 0.10482 0.418767 0.902024 +vn 0.282768 0.019592 0.958988 +vn 0.116446 0.0713892 0.990628 +vn 0.489202 0.398612 0.775751 +vn 0.329144 -0.121201 0.936469 +vn 0.455362 -0.405814 0.792439 +vn 0.924068 -0.0737695 0.375043 +vn 0.726583 -0.406136 -0.554193 +vn 0.912128 -0.258876 -0.317814 +vn 0.37622 -0.539218 -0.75346 +vn 0.235179 -0.0902081 0.967757 +vn 0.894128 0.0166594 0.447501 +vn 0.496565 -0.108946 0.861135 +vn 0.312314 -0.184811 0.931829 +vn 0.10077 -0.173246 0.97971 +vn -0.0268722 -0.294784 0.955186 +vn 0.822977 0.0718507 -0.563512 +vn 0.813641 0.284049 0.507252 +vn 0.520357 0.071308 0.850966 +vn -0.706032 0.0868972 -0.702828 +vn -0.675916 0.166752 0.717866 +vn -0.742328 0.592029 -0.313769 +vn 0.766762 -0.577424 0.280458 +vn 0.868298 -0.398143 -0.295875 +vn 0.992001 0.109234 -0.063255 +vn 0.0318571 -0.116446 0.992686 +vn 0.692294 -0.435164 -0.57564 +vn 0.767695 -0.464319 0.441646 +vn 0.815829 -0.512369 -0.268143 +vn 0.390525 -0.312124 0.866065 +vn -0.587214 -0.314648 -0.745772 +vn -0.879151 -0.430737 -0.203863 +vn 0.379797 -0.825445 -0.417605 +vn 0.688512 0.0683362 -0.721998 +vn -0.880545 -0.242142 -0.407441 +vn -0.146388 -0.564456 0.812379 +vn -0.835651 -0.483096 0.261353 +vn -0.464799 -0.300084 0.833013 +vn 0.951908 0.04638 0.302855 +vn 0.146635 -0.580864 -0.800684 +vn -0.160148 0.258184 -0.95273 +vn -0.93963 -0.0857132 -0.331283 +vn -0.890278 -0.260318 -0.373685 +vn -0.44408 -0.485958 -0.752754 +vn 0.892954 -0.0903132 -0.440995 +vn 0.7404 -0.520321 0.425527 +vn 0.886944 0.108506 -0.448951 +vn -0.0655223 -0.20826 0.975876 +vn 0.8694 -0.493145 -0.0308514 +vn -0.209507 -0.206382 0.955779 +vn -0.688857 0.655103 -0.310348 +vn 0.474474 0.872164 -0.119179 +vn -0.693846 0.61035 0.382166 +vn -0.837219 0.0380246 -0.545545 +vn 0.599863 0.524678 -0.60405 +vn -0.950716 0.220629 -0.217856 +vn -0.0842885 0.41714 0.904925 +vn -0.417776 0.368932 0.830273 +vn 0.933339 0.33561 0.12745 +vn -0.0320392 -0.116325 0.992694 +vn -0.128567 0.0726206 0.989038 +vn -0.76671 -0.577336 0.280785 +vn -0.45526 -0.405662 0.792576 +vn -0.924043 -0.0737542 0.375107 +vn -0.91218 -0.258888 -0.317655 +vn -0.820592 -0.347264 -0.453912 +vn -0.857076 -0.317563 -0.405678 +vn -0.804063 0.0191818 0.594234 +vn -0.27732 -0.19989 0.939754 +vn -0.496506 -0.10892 0.861173 +vn 0.287494 -0.38728 0.875992 +vn -0.237655 -0.0510188 0.970009 +vn -0.900605 0.275826 0.335901 +vn -0.994763 0.0447804 -0.0918816 +vn -0.900405 0.051913 -0.431945 +vn -0.346572 -0.00873903 0.937983 +vn 0.872538 0.482562 -0.0762303 +vn -0.868375 -0.39816 -0.295623 +vn -0.767625 -0.464201 0.441893 +vn -0.543145 0.139718 0.827933 +vn 0.69051 0.591543 -0.41626 +vn 0.692335 0.176594 -0.699633 +vn -0.352553 -0.122519 0.927737 +vn -0.165885 -0.234183 0.957935 +vn -0.815914 -0.512405 -0.267815 +vn -0.39045 -0.312007 0.866141 +vn 0.736563 0.228111 0.636742 +vn 0.890475 0.190401 -0.413282 +vn 0.629954 -0.243575 0.737448 +vn -0.0923351 0.773121 -0.627501 +vn -0.788384 0.230783 0.570254 +vn -0.886614 0.124781 -0.44536 +vn 0.205807 0.338162 -0.918308 +vn 0.0748491 -0.356353 -0.931348 +vn 0.999016 0.0221839 -0.0384006 +vn -0.443791 0.25015 -0.860508 +vn -0.0012295 -0.346731 0.937964 +vn -0.997408 -0.0567095 0.0442766 +vn -0.492626 -0.350197 0.796669 +vn 0.637903 0.257154 0.725914 +vn 0.852375 0.428329 -0.299985 +vn 0.62633 -0.236363 0.742862 +vn -0.217103 0.834688 -0.506124 +vn -0.848527 -0.0280145 0.528409 +vn -0.868015 0.0219495 -0.496052 +vn 0.180019 0.522134 -0.833648 +vn 0.196954 -0.172102 -0.965189 +vn 0.973227 0.223794 0.052394 +vn -0.439262 0.300005 -0.846786 +vn 0.0204926 -0.493628 0.869432 +vn -0.964806 -0.257802 -0.0518397 +vn -0.451177 -0.569444 0.687148 +vn 0.608577 0.503701 0.613123 +vn 0.862128 0.311106 -0.399936 +vn 0.597742 0.0466846 0.800328 +vn -0.199712 0.603141 -0.772228 +vn -0.8683 0.143643 0.474786 +vn -0.848224 -0.165858 -0.502998 +vn 0.210695 0.202722 -0.956301 +vn 0.234613 -0.493806 -0.837325 +vn 0.969821 0.243755 0.00562993 +vn -0.407019 -0.0201329 -0.913198 +vn -0.0118125 -0.160323 0.986994 +vn -0.961326 -0.275321 0.00707957 +vn -0.475846 -0.302378 0.825916 +vn -0.468118 0.353108 0.810049 +vn -0.302633 0.618541 -0.725135 +vn 0.978009 0.0456435 0.203508 +vn 0.374276 -0.261743 0.889611 +vn -0.309901 -0.0734365 0.947928 +vn -0.960156 0.275703 0.0456929 +vn -0.628833 0.305296 -0.715097 +vn 0.0062432 -0.554648 -0.832061 +vn -0.952529 0.20147 0.228251 +vn 0.670352 -0.350031 0.654298 +vn 0.324792 0.0121434 -0.945707 +vn 0.703865 -0.0933096 -0.704179 +vn 0.939164 -0.231128 -0.254069 +vn -0.503142 0.207778 0.838854 +vn -0.212617 0.778035 -0.591147 +vn 0.961907 -0.0701879 0.264213 +vn 0.293338 -0.470186 0.832393 +vn -0.380839 -0.248705 0.890566 +vn -0.942862 0.329577 0.0488999 +vn -0.556745 0.494529 -0.667439 +vn 0.0326928 -0.365744 -0.930141 +vn -0.952757 0.218167 0.211322 +vn 0.599741 -0.528367 0.600949 +vn 0.391834 0.187405 -0.900747 +vn 0.745696 0.00586267 -0.66626 +vn 0.939537 -0.24066 -0.243626 +vn -0.568956 0.0888671 0.817552 +vn -0.347922 0.721576 -0.598564 +vn 0.943645 0.131386 0.303762 +vn 0.352167 -0.406012 0.843287 +vn -0.355336 -0.332098 0.873755 +vn -0.992344 0.123084 0.0101823 +vn -0.621187 0.372703 -0.689361 +vn 0.14654 -0.341579 -0.928359 +vn -0.985051 0.0104906 0.171941 +vn 0.672987 -0.39607 0.624674 +vn 0.379436 0.274584 -0.883534 +vn 0.7539 0.169349 -0.634788 +vn 0.978188 -0.0349604 -0.204758 +vn -0.306682 -0.0763865 0.948742 +vn 0.306682 0.0763865 -0.948742 +vn -0.514461 -0.178648 0.838698 +vn 0.514461 0.178648 -0.838698 +vn -0.431693 -0.312498 0.84616 +vn 0.431693 0.312498 -0.84616 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.0366585 -0.34951 0.936215 +vn 0.0366585 0.34951 -0.936215 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.153422 0.458892 -0.875146 +vn 0.153422 -0.458892 0.875146 +vn -0.0428895 0.146604 -0.988265 +vn 0.0428895 -0.146604 0.988265 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0.182939 0.532381 -0.826501 +vn -0.182939 -0.532381 0.826501 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0.305931 0.0766449 -0.948963 +vn -0.305931 -0.0766449 0.948963 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0.94086 0.00597124 -0.338743 +vn 0.259548 -0.183775 0.948083 +vn 0.546247 -0.806783 0.225199 +vn 0.402958 -0.133648 0.905408 +vn -0.259869 0.86542 0.428388 +vn -0.116329 -0.25209 0.960686 +vn -0.00239429 0.714675 0.699453 +vn -0.0483536 0.592988 -0.803758 +vn -0.481549 0.771171 -0.416421 +vn -0.458242 0.633725 0.623223 +vn -0.24949 0.768874 -0.588717 +vn 0.10864 -0.257435 -0.960169 +vn 0.325716 -0.478002 -0.815735 +vn -0.0225388 -0.180561 -0.983305 +vn 0.406471 -0.909723 0.0847693 +vn 0.206639 -0.978195 -0.0208281 +vn 0.157984 -0.100322 0.982332 +vn 0.0510307 -0.0676364 0.996404 +vn -0.377967 0.789777 0.483108 +vn -0.312692 0.844495 0.4348 +vn -0.284092 0.652331 -0.702677 +vn 0.217682 -0.0287339 -0.975597 +vn 0.397327 -0.917647 0.00745435 +vn 0.358071 -0.823869 0.439346 +vn 0.165922 -0.335601 0.927277 +vn -0.502785 0.706935 0.497444 +vn -0.364144 0.618789 -0.69606 +vn -0.090366 0.0601771 -0.994089 +vn 0.186925 0.201056 -0.96158 +vn 0.758373 -0.634704 -0.148395 +vn 0.0958113 -0.99107 0.0927416 +vn -0.831103 0.240499 0.501426 +vn -0.675473 0.274544 -0.684369 +vn 0.583947 -0.453778 -0.673121 +vn -0.812062 0.264974 -0.519946 +vn 0.135246 -0.527536 0.838698 +vn -0.502879 -0.244522 0.829049 +vn -0.399268 -0.0752793 -0.913738 +vn 0.00200453 -0.932761 -0.36049 +vn -0.743749 -0.526364 0.412041 +vn -0.984915 0.148944 0.0880841 +vn 0.53607 -0.762862 0.361484 +vn -0.743138 -0.39008 0.543676 +vn -0.653546 -0.669285 -0.353462 +vn 0.242984 -0.591911 -0.768506 +vn 0.63005 -0.607898 0.483215 +vn 0.638484 -0.404625 -0.654689 +vn 0.448103 0.389566 0.804638 +vn 0.1295 0.601421 -0.788367 +vn 0.0219642 0.990339 0.136915 +vn 0.912524 0.406502 -0.0453377 +vn -0.259882 -0.184638 0.947824 +vn 0.259221 0.865223 0.429177 +vn 0.00251004 0.712214 0.701957 +vn -0.403476 -0.135884 0.904844 +vn -0.547168 -0.806779 0.222966 +vn -0.206309 -0.978256 -0.0212441 +vn 0.11632 -0.252108 0.960683 +vn 0.0480316 0.594177 -0.802899 +vn 0.250688 0.771151 -0.58522 +vn 0.458244 0.633724 0.623223 +vn -0.325583 -0.476163 -0.816862 +vn -0.106632 -0.253188 -0.961522 +vn 0.481489 0.771222 -0.416395 +vn -0.406603 -0.910107 0.0798638 +vn 0.0228005 -0.180428 -0.983324 +vn -0.159292 -0.104165 0.981721 +vn 0.312026 0.842561 0.43901 +vn 0.377155 0.787512 0.487421 +vn 0.285873 0.655753 -0.69876 +vn -0.215669 -0.0235027 -0.976184 +vn -0.397904 -0.917426 0.00141454 +vn -0.0529169 -0.0722659 0.995981 +vn -0.35886 -0.826006 0.434665 +vn 0.502271 0.706031 0.499243 +vn -0.166439 -0.337641 0.926443 +vn 0.365378 0.620296 -0.69407 +vn 0.0924268 0.0649903 -0.993596 +vn -0.75823 -0.633781 -0.153001 +vn -0.0969265 -0.991322 0.0888019 +vn 0.675582 0.274642 -0.684223 +vn -0.583648 -0.452186 -0.67445 +vn -0.184919 0.206339 -0.960848 +vn 0.812936 0.267516 -0.517272 +vn 0.83095 0.240578 0.501642 +vn 0.501159 -0.249758 0.828529 +vn -0.135675 -0.527627 0.838571 +vn 0.40045 -0.0702721 -0.91362 +vn 0.74328 -0.528967 0.409547 +vn 0.984828 0.148573 0.0896604 +vn -0.00181066 -0.930449 -0.366417 +vn 0.743137 -0.390081 0.543676 +vn 0.653546 -0.669285 -0.353461 +vn -0.242985 -0.59191 -0.768506 +vn -0.53607 -0.762862 0.361484 +vn -0.638483 -0.404624 -0.65469 +vn -0.630052 -0.607897 0.483214 +vn -0.448104 0.389565 0.804638 +vn -0.1295 0.601423 -0.788366 +vn -0.0219644 0.990339 0.136918 +vn -0.912524 0.406502 -0.0453371 +vn -0.0904868 0.122157 0.988377 +vn 0.788667 0.0598377 0.611902 +vn -0.0851441 0.228746 0.969755 +vn -0.912005 0.070267 0.404115 +vn -0.779994 -0.129824 0.612173 +vn -0.114086 -0.235973 0.96504 +vn -0.94194 0.0749635 0.327308 +vn -0.850191 -0.111313 -0.514572 +vn -0.994977 0.0736684 0.06778 +vn -0.797917 -0.0785221 -0.597631 +vn 0.0633305 -0.149929 -0.986666 +vn -0.0144205 -0.328453 -0.94441 +vn -0.0661901 -0.351253 -0.933938 +vn 0.00362937 -0.363955 -0.931409 +vn -0.862979 -0.258597 -0.434045 +vn 0.882972 -0.199764 -0.4248 +vn 0.906752 -0.13792 -0.39847 +vn 0.869574 0.00971647 0.493706 +vn 0.961227 0.0285432 0.274277 +vn 0.617364 -0.188602 0.763735 +vn -0.0349204 0.0346149 0.99879 +vn -0.917701 0.0942612 0.385928 +vn -0.948916 -0.0777991 0.305787 +vn -0.0851002 -0.158452 0.983693 +vn 0.929513 -0.018439 0.368328 +vn 0.0274214 0.215213 0.976182 +vn -0.93494 0.151583 -0.320796 +vn -0.898308 0.0350296 0.437968 +vn -0.953092 -0.286574 0.0974204 +vn -0.86367 0.326167 -0.384303 +vn -0.0439373 0.428525 -0.902461 +vn -0.122272 0.0824013 -0.98907 +vn -0.781019 -0.0700118 -0.62057 +vn 0.905261 0.0520618 -0.421654 +vn 0.765074 -0.151685 -0.625822 +vn 0.956714 -0.288801 -0.0359618 +vn 0.931166 -0.068561 0.358092 +vn 0.86636 0.1683 -0.470208 +vn 0.842129 -0.16835 0.512325 +vn -0.0810366 -0.103821 0.991289 +vn -0.168201 -0.0976165 -0.980907 +vn 0.824518 -0.319861 -0.466754 +vn -0.0550432 -0.462048 -0.885145 +vn 0.0558041 -0.487541 0.871315 +vn -0.658127 -0.722839 0.210647 +vn -0.84109 -0.137863 0.52303 +vn 0.0776385 -0.158345 0.984327 +vn 0.909755 -0.236585 0.341135 +vn 0.731114 -0.67743 0.0810027 +vn -0.617465 -0.652547 -0.439226 +vn -0.768048 -0.254281 -0.587744 +vn 0.204208 -0.760921 -0.615871 +vn 0.631103 -0.342957 -0.695765 +vn -0.824497 0.434977 -0.36194 +vn -0.764872 -0.51188 0.391087 +vn -0.638618 0.293868 -0.711203 +vn 0.00153731 0.733887 -0.67927 +vn 0.0104973 0.580558 -0.814151 +vn -0.791372 -0.1251 0.598398 +vn 0.854507 0.344845 -0.388458 +vn 0.434303 0.309356 -0.845978 +vn 0.760327 -0.637954 0.122138 +vn 0.637906 -0.363244 0.679065 +vn 0.487013 -0.493277 -0.720761 +vn -0.448138 -0.543745 -0.709587 +vn 0.0580331 -0.151122 0.98681 +vn 0.962418 0.2653 0.0580229 +vn 0.925809 0.0554412 0.373903 +vn -0.986534 0.146599 0.0725244 +vn -0.0115616 -0.362065 -0.932081 +vn -0.963615 0.26161 0.054831 +vn -0.0991855 -0.373682 0.922239 +vn 0.684621 -0.159107 -0.711322 +vn 0.0414428 0.887453 0.459032 +vn 0.338438 -0.234898 0.911199 +vn 0.0551588 0.833726 -0.549417 +vn -0.552152 -0.216387 0.805174 +vn -0.684959 -0.0945815 -0.722416 +vn 0.0688383 0.997134 -0.0313777 +vn 0.0861184 0.233058 0.968642 +vn 0.911686 0.0949881 0.399757 +vn 0.0851543 0.228731 0.969758 +vn -0.78883 0.105437 0.605501 +vn -0.633256 -0.109803 0.766114 +vn 0.113182 -0.183409 0.976499 +vn 0.848691 -0.148025 -0.507751 +vn 0.941941 0.0749595 0.327304 +vn 0.788855 -0.0671203 0.610904 +vn 0.994492 0.0792526 0.0685909 +vn 0.0189257 -0.429591 -0.902825 +vn -0.00363056 -0.363897 -0.931432 +vn 0.07044 -0.462199 -0.883974 +vn -0.879143 -0.22911 -0.417871 +vn -0.869569 0.00971176 0.493717 +vn -0.0633316 -0.149925 -0.986667 +vn -0.824833 -0.339293 -0.452251 +vn -0.96003 0.055632 0.274313 +vn 0.034925 0.034617 0.99879 +vn -0.929517 -0.0184329 0.368317 +vn -0.842161 -0.168369 0.512267 +vn 0.0851049 -0.158499 0.983684 +vn 0.917703 0.0942646 0.385922 +vn -0.0274175 0.215228 0.976179 +vn 0.934939 0.151562 -0.320808 +vn 0.898307 0.0350278 0.437971 +vn 0.948936 -0.0778124 0.305722 +vn 0.953091 -0.286579 0.0974205 +vn 0.122279 0.082368 -0.989072 +vn 0.0439447 0.428479 -0.902483 +vn 0.780999 -0.0700118 -0.620596 +vn -0.905259 0.0520415 -0.42166 +vn 0.168194 -0.0976165 -0.980909 +vn -0.765062 -0.151683 -0.625838 +vn -0.931163 -0.0685608 0.358098 +vn -0.956713 -0.288803 -0.0359606 +vn -0.866358 0.168291 -0.470215 +vn 0.0810411 -0.103852 0.991286 +vn 0.797896 -0.0785227 -0.597659 +vn -0.906741 -0.137921 -0.398495 +vn 0.863001 -0.280439 -0.420218 +vn -0.0558044 -0.487541 0.871315 +vn 0.658127 -0.722839 0.210646 +vn -0.731114 -0.67743 0.0810021 +vn -0.909755 -0.236584 0.341135 +vn 0.617464 -0.652546 -0.439228 +vn -0.204208 -0.760921 -0.615872 +vn 0.841091 -0.137864 0.52303 +vn 0.768047 -0.254281 -0.587746 +vn -0.631103 -0.342958 -0.695765 +vn 0.824497 0.434977 -0.36194 +vn -0.0104981 0.580558 -0.814151 +vn -0.00153743 0.733887 -0.67927 +vn 0.764872 -0.51188 0.391088 +vn 0.791372 -0.125101 0.598399 +vn -0.854507 0.344844 -0.388458 +vn 0.863671 0.326157 -0.384311 +vn -0.760327 -0.637954 0.122138 +vn -0.434303 0.309357 -0.845978 +vn -0.637906 -0.363245 0.679065 +vn 0.448138 -0.543744 -0.709588 +vn 0.638617 0.293868 -0.711203 +vn -0.0580336 -0.151122 0.98681 +vn -0.0776405 -0.158345 0.984326 +vn -0.487014 -0.493275 -0.720761 +vn 0.0550209 -0.461953 -0.885196 +vn -0.962443 0.26519 0.0581157 +vn -0.925815 0.055559 0.373872 +vn 0.986521 0.14671 0.0724734 +vn 0.963645 0.261496 0.0548557 +vn 0.0992104 -0.373815 0.922182 +vn -0.684589 -0.159113 -0.711351 +vn -0.0414311 0.887273 0.45938 +vn 0.0115571 -0.362006 -0.932104 +vn -0.338504 -0.234953 0.91116 +vn -0.0551812 0.833981 -0.549027 +vn 0.552264 -0.216436 0.805084 +vn 0.684923 -0.0945817 -0.72245 +vn -0.0688326 0.997145 -0.0310416 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.514858 -0.391796 0.762507 +vn -0.562269 0.00389389 0.826945 +vn -0.25973 -0.41688 0.871063 +vn 0.340812 -0.659266 0.670235 +vn -0.571668 -0.612703 0.545701 +vn -0.803593 -0.326944 0.497339 +vn -0.858009 -0.0214501 0.513186 +vn -0.262765 -0.114728 0.958015 +vn -0.911096 0.285619 0.297196 +vn -0.650686 0.341028 0.67846 +vn -0.352378 0.370658 0.859326 +vn -6.65331e-006 -0.237412 -0.971409 +vn -0.135205 0.00499796 -0.990805 +vn 0.866195 -0.479156 -0.141831 +vn -0.365716 -0.0144208 -0.930615 +vn -0.405571 0.70824 -0.577848 +vn -0.778646 0.430358 -0.45662 +vn -0.504496 -0.184138 -0.84355 +vn 0.000100324 0.975598 -0.219565 +vn 7.69033e-005 0.971693 0.236246 +vn -0.0898036 0.961294 -0.26048 +vn 4.44925e-005 0.792109 -0.610379 +vn 0.0899669 0.961283 -0.260463 +vn -0.853948 0.483539 -0.192258 +vn -0.662236 0.652564 0.368245 +vn -0.975689 0.10642 -0.191589 +vn -0.908857 0.0889791 -0.407507 +vn -0.483541 0.864422 -0.137706 +vn -0.328074 0.806091 0.492528 +vn 0.483624 0.86438 -0.137682 +vn 0.328119 0.805912 0.492792 +vn -0.84331 -0.112147 -0.525596 +vn -0.926183 0.090517 -0.36605 +vn -0.461444 0.418594 -0.782208 +vn 0.462223 0.542344 -0.701579 +vn -0.978064 -0.0428504 -0.20385 +vn -0.929292 -0.351291 -0.114067 +vn -0.950607 -0.117201 -0.287419 +vn -0.307578 -0.178812 -0.934571 +vn 1.35122e-005 0.524659 0.851312 +vn -0.358721 -0.783479 0.507425 +vn -3.97743e-007 0.00258734 0.999997 +vn -0.535214 -0.835009 0.127692 +vn -0.0677187 -0.534441 0.842489 +vn 0.895046 0.315416 -0.315286 +vn 0.000390124 -0.496173 0.868223 +vn 0.870888 -0.46927 0.146083 +vn 0.135082 0.00435294 -0.990825 +vn 0.405621 0.70785 -0.578291 +vn -0.964661 -0.188824 -0.183778 +vn -0.0286472 -0.0116998 -0.999521 +vn -0.922946 -0.27789 -0.266359 +vn 0.42179 -0.737991 0.526747 +vn -0.966818 -0.057737 -0.248856 +vn -0.572602 -0.685054 0.450365 +vn -0.311415 0.546847 -0.777161 +vn -0.968822 -0.216208 -0.120991 +vn 0.352364 0.370317 0.859479 +vn 0.158629 -0.653105 0.740466 +vn 0.993836 0.106307 -0.0314576 +vn -0.965176 -0.153597 -0.211762 +vn -0.17516 0.539486 -0.823574 +vn 0.9 0.317773 -0.298362 +vn 0.844997 -0.527193 -0.08971 +vn 0.782965 0.2831 -0.553914 +vn -0.117725 0.359964 -0.925509 +vn -0.179726 -0.703355 -0.687743 +vn 0.0514783 -0.56084 0.826322 +vn -0.945399 0.286875 -0.154674 +vn -0.890727 -0.0905954 -0.445419 +vn 0.509516 -0.187927 0.839689 +vn -0.923166 -0.365949 -0.117667 +vn 0.0807092 -0.320609 0.943767 +vn 0.554196 0.490455 -0.672548 +vn 0.513121 0.222572 -0.828956 +vn -0.829515 0.158791 0.535435 +vn -0.56288 0.249313 -0.788041 +vn -0.728582 -0.671721 0.134008 +vn 0.262765 -0.114731 0.958014 +vn 0.25973 -0.41688 0.871064 +vn -0.872648 -0.466233 0.145299 +vn 0.514858 -0.391795 0.762507 +vn 0.562268 0.00388284 0.826946 +vn 0.857761 -0.0159718 0.5138 +vn 0.577754 -0.610583 0.541653 +vn -0.340811 -0.659266 0.670236 +vn 0.794927 -0.328751 0.509915 +vn 0.912374 0.28284 0.295933 +vn 0.364884 -0.0130801 -0.930961 +vn 0.50425 -0.186262 -0.843231 +vn 0.779186 0.42823 -0.457698 +vn -0.864971 -0.485207 -0.128058 +vn 0.854839 0.482034 -0.192079 +vn 0.662882 0.651558 0.368862 +vn 0.908583 0.0859513 -0.408765 +vn 0.65082 0.339934 0.67888 +vn 0.845256 -0.105775 -0.523788 +vn 0.925918 0.102841 -0.363455 +vn 0.978393 -0.0316501 -0.204317 +vn 0.933992 -0.339757 -0.110559 +vn 0.37757 -0.770141 0.514125 +vn -0.461827 0.541347 -0.702609 +vn 0.450982 0.422532 -0.786182 +vn 0.965541 -0.0771152 -0.248564 +vn 0.976278 0.104405 -0.189689 +vn 0.951492 -0.100346 -0.290849 +vn 0.535217 -0.835008 0.127691 +vn 0.0677214 -0.534442 0.842488 +vn 0.890727 -0.0905947 -0.44542 +vn -0.895047 0.315416 -0.315285 +vn 0.297553 -0.189878 -0.935633 +vn 0.968937 -0.166781 -0.182605 +vn 0.0184428 -0.00806701 -0.999797 +vn 0.990737 -0.107913 -0.0824336 +vn 0.614601 -0.605438 0.505678 +vn 0.314396 0.567862 -0.760715 +vn -0.404938 -0.754318 0.51675 +vn -0.993836 0.106307 -0.0314578 +vn -0.319288 -0.634959 0.703478 +vn -0.896452 0.238197 -0.37368 +vn 0.0736654 0.512059 -0.855786 +vn 0.941372 -0.0156091 -0.33701 +vn -0.978821 0.198976 -0.0481399 +vn -0.775181 0.321845 -0.543609 +vn -0.401231 -0.533556 0.744535 +vn -0.793597 0.414147 -0.445743 +vn 0.103707 0.389007 -0.915379 +vn 0.794323 -0.599733 0.0968053 +vn 0.922407 -0.279441 -0.266603 +vn -0.0825262 -0.315773 0.945239 +vn -0.514699 0.199904 -0.833741 +vn -0.511472 -0.184001 0.839369 +vn 0.914449 -0.38666 -0.119488 +vn -0.541082 0.510032 -0.668653 +vn 0.628502 -0.419027 -0.655287 +vn -0.730706 -0.384589 -0.564056 +vn 0.0221406 0.366461 -0.93017 +vn -4.79821e-007 0.360952 -0.932584 +vn -0.289325 0.367231 -0.883987 +vn 0.00199152 0.341981 -0.939705 +vn 0.280006 0.381312 -0.881021 +vn -0.651807 0.219407 -0.725953 +vn -0.870795 -0.0966788 -0.482047 +vn -0.663674 0.204489 -0.719529 +vn -0.846815 -0.29515 -0.442482 +vn -0.847469 -0.296729 -0.440168 +vn 0.00162418 0.212394 -0.977183 +vn -0.275172 0.264539 -0.924283 +vn 0.263242 0.193249 -0.945176 +vn 0.259161 0.258561 -0.930582 +vn -0.573232 0.153014 -0.80498 +vn -0.257122 0.174875 -0.950425 +vn -0.866846 -0.0341655 -0.497404 +vn 0.679464 0.269828 -0.682292 +vn 0.659307 0.183319 -0.729183 +vn 0.862563 -0.179377 -0.473085 +vn 0.857146 -0.160599 -0.489396 +vn 0.788004 -0.435002 -0.435687 +vn 0.781225 -0.370199 -0.502633 +vn 0.55503 0.105996 -0.825049 +vn 0.98695 -0.160736 -0.00972412 +vn -0.0385398 -0.955624 -0.292057 +vn -0.04497 -0.442003 0.895886 +vn 0.000551811 0.182304 -0.983242 +vn -0.987694 -0.143835 -0.0614255 +vn -0.109758 0.926248 0.360579 +vn -0.98695 -0.160736 -0.00972482 +vn 0.0385383 -0.955624 -0.292058 +vn -0.000553969 0.182304 -0.983242 +vn 0.109757 0.926254 0.360564 +vn 0.0449713 -0.442003 0.895886 +vn 0.987693 -0.143834 -0.0614296 +vn -1.3174e-006 -0.00583225 0.999983 +vn -0.585608 0.240289 0.77416 +vn -3.41425e-007 0.296427 0.955056 +vn 0.58561 0.240274 0.774164 +vn 6.44766e-007 0.565498 0.82475 +vn -0.420142 0.0995062 -0.901986 +vn -1.32414e-006 -0.208414 -0.978041 +vn -2.48538e-007 0.109653 -0.99397 +vn 8.26749e-007 0.414081 -0.91024 +vn 0.420141 0.0995053 -0.901987 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.896506 -0.1163 0.427494 +vn 0.896506 0.1163 -0.427494 +vn 0.766092 -0.357818 0.533919 +vn -0.766092 0.357818 -0.533919 +vn 0.442469 -0.190715 0.87627 +vn -0.442469 0.190715 -0.87627 +vn -0.445083 -0.187013 0.875744 +vn 0.445083 0.187013 -0.875744 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn 0 0 0 +vn -0.0998351 0.0857727 -0.9913 +vn 0.0998351 -0.0857727 0.9913 +vn -0.835474 0.261484 -0.483332 +vn 0.835474 -0.261484 0.483332 +vn 0.792232 0.279543 -0.542424 +vn -0.792232 -0.279543 0.542424 +vn 0.472778 0.152571 -0.867873 +vn -0.472778 -0.152571 0.867873 +vn 1.72369e-006 0.0565094 -0.998402 +vn 1.90769e-006 -0.116814 -0.993154 +vn -0.418301 -0.283028 -0.863087 +vn 3.46478e-007 0.0446885 -0.999001 +vn 0.578399 0.0572155 -0.813745 +vn 0.418302 -0.283032 -0.863086 +vn -0.5784 0.057215 -0.813744 +vn -0.554727 -0.11319 -0.824297 +vn 8.29038e-007 -0.468281 -0.88358 +vn 0.554934 -0.113966 -0.824051 +vn 0.000876554 -0.195229 -0.980757 +vn 7.21149e-007 0.236454 -0.971643 +vn 4.29442e-006 0.329828 -0.944041 +vn -0.261521 0.34336 -0.902059 +vn 0.345106 -0.112745 -0.931767 +vn 0.391981 0.273749 -0.878301 +vn 0.261524 0.343368 -0.902055 +vn -0.345106 -0.112739 -0.931768 +vn 0.00105863 -0.447489 -0.894289 +vn -0.396475 -0.280215 -0.874235 +vn 0.000881516 -0.462635 -0.886548 +vn 0.397754 -0.280007 -0.873721 +vn 0.00108685 -0.664596 -0.747202 +vn 0.000915718 -0.442049 -0.89699 +vn -0.390565 -0.422608 -0.817839 +vn 0.000861405 -0.988847 -0.14893 +vn 0.444539 -0.765114 -0.465818 +vn 0.391688 -0.422435 -0.817391 +vn -0.443472 -0.765525 -0.466159 +vn -0.349514 -0.934982 0.0603993 +vn -0.0085034 -0.967111 -0.254214 +vn 0.351495 -0.934507 0.0561049 +vn -3.85435e-007 -0.668437 0.743768 +vn -2.28351e-008 -0.162416 0.986722 +vn -0.640378 -0.442255 0.627954 +vn 0.546387 -0.470661 0.692777 +vn 0.640377 -0.442259 0.627952 +vn 6.43996e-008 0.122791 0.992433 +vn -0.617739 0.0960915 0.78049 +vn 0.617739 0.0960848 0.780491 +vn -0.553176 -0.773347 -0.309728 +vn -0.00650466 -0.243615 -0.96985 +vn 0.555572 -0.77263 -0.307217 +vn -0.688882 -0.144744 -0.710275 +vn 0.00100529 -0.272155 -0.962253 +vn -0.422032 -0.0447178 -0.905477 +vn -0.282574 -0.28798 -0.914997 +vn -0.215431 -0.0509653 -0.975188 +vn -0.375565 -0.303024 -0.875858 +vn -0.668722 -0.0625792 -0.740874 +vn -0.548509 -0.179042 -0.816751 +vn -0.430371 -0.0688108 -0.900026 +vn -0.391974 0.273741 -0.878306 +vn -0.850233 -0.110695 -0.514635 +vn -0.607396 -0.0793708 -0.790424 +vn -0.647842 0.25879 -0.716469 +vn -0.713809 -0.116372 -0.690604 +vn -0.948292 0.174671 -0.265014 +vn -0.932139 -0.10227 -0.347359 +vn -0.90945 -0.208442 -0.359796 +vn -0.550725 -0.0780384 -0.831031 +vn -0.913541 -0.2697 -0.304474 +vn -0.366391 -0.000195607 -0.930461 +vn -0.427668 -0.170469 -0.887716 +vn -0.421646 -0.160265 -0.892485 +vn -0.664073 -0.421344 -0.617637 +vn -0.766117 -0.642694 0.00300611 +vn -0.843843 -0.510886 -0.164086 +vn -0.623092 -0.760727 -0.181802 +vn -0.652587 -0.756341 0.0455867 +vn -0.838957 0.536659 0.0902655 +vn -0.649068 0.0890654 -0.755499 +vn -0.408228 -0.817531 0.406192 +vn -0.706085 -0.697793 -0.120532 +vn -0.676867 -0.685535 0.268127 +vn -0.364382 -0.512778 0.777357 +vn -0.998907 -0.0101226 0.0456405 +vn -0.844641 0.283192 0.454294 +vn 0.314136 -0.0937636 0.944737 +vn -0.546389 -0.470657 0.692778 +vn -0.637034 -0.690054 0.34353 +vn 0.42839 -0.171896 -0.887093 +vn -0.309322 0.276956 -0.909734 +vn -0.849984 -0.417733 -0.320978 +vn 0.289861 0.883525 -0.367917 +vn -0.560146 0.350429 -0.750623 +vn 0.453342 0.864652 -0.216469 +vn 0.240381 -0.11546 0.963787 +vn 0.422032 -0.0447175 -0.905477 +vn 0.282574 -0.28798 -0.914997 +vn 0.366425 -0.00162436 -0.930446 +vn 0.215432 -0.0509649 -0.975188 +vn 0.375563 -0.303029 -0.875857 +vn 0.548507 -0.179046 -0.816751 +vn 0.669498 -0.0624052 -0.740188 +vn 0.43037 -0.0688113 -0.900026 +vn 0.607396 -0.0793713 -0.790424 +vn 0.85047 -0.11012 -0.514368 +vn 0.948076 0.176394 -0.264646 +vn 0.649166 0.258553 -0.715355 +vn 0.710934 -0.109192 -0.69473 +vn 0.912522 -0.190272 -0.362078 +vn 0.933244 -0.0977595 -0.345685 +vn 0.544789 -0.0783306 -0.834907 +vn 0.911968 -0.269082 -0.309692 +vn 0.421522 -0.161716 -0.892282 +vn 0.660191 -0.425581 -0.618893 +vn 0.837789 -0.521475 -0.161783 +vn 0.762074 -0.647463 0.00585336 +vn 0.623095 -0.760725 -0.181799 +vn 0.652262 -0.756648 0.0451528 +vn 0.837876 0.53861 0.0886794 +vn 0.844413 0.285522 0.453259 +vn 0.705847 -0.697961 -0.120952 +vn 0.649063 0.0890657 -0.755503 +vn 0.416354 -0.816039 0.400911 +vn 0.678491 -0.68222 0.272445 +vn 0.700123 -0.151104 -0.697851 +vn 0.364381 -0.512778 0.777358 +vn -0.289861 0.883526 -0.367917 +vn -0.314132 -0.0937597 0.944738 +vn 0.998907 -0.0101328 0.0456407 +vn 0.637033 -0.690054 0.343532 +vn 0.849983 -0.417733 -0.32098 +vn 0.309322 0.276956 -0.909734 +vn 0.560147 0.350427 -0.750624 +vn -0.24038 -0.115461 0.963787 +vn -0.453343 0.864651 -0.216468 +vn -5.94196e-008 0.953809 0.300412 +vn -0.131656 0.932138 -0.337322 +vn -1.16908e-007 0.0880425 0.996117 +vn 0.131657 0.932138 -0.337322 +vn 6.86108e-007 0.826624 0.562755 +vn -0.0812812 0.817112 0.57072 +vn 4.0183e-007 0.646868 -0.762602 +vn 0.0812817 0.817112 0.57072 +vn -0.60209 -0.427259 0.674491 +vn -0.315312 -0.398044 0.861475 +vn -2.98966e-007 -0.484791 0.87463 +vn -0.834834 0.278081 -0.475103 +vn -0.451215 0.584701 -0.674188 +vn -0.0672212 0.951229 -0.301073 +vn -0.738411 -0.449038 0.503104 +vn 0.0781483 0.899901 -0.429035 +vn 0.127011 0.888445 -0.441059 +vn -0.285316 0.824732 -0.488275 +vn -0.436172 0.632969 -0.639612 +vn 0.242243 0.626065 -0.741189 +vn -0.147276 0.790178 -0.594918 +vn -0.926583 0.320373 -0.19699 +vn 7.09764e-008 0.404717 -0.914442 +vn -0.624756 0.108174 -0.773291 +vn 9.69619e-008 0.662732 -0.748856 +vn 0.147274 0.790179 -0.594918 +vn 0.624756 0.108174 -0.77329 +vn 0.339057 -0.12191 -0.932834 +vn 1.90474e-007 -0.187151 0.982331 +vn -0.160504 -0.173398 0.971685 +vn -0.274753 0.0248081 0.961195 +vn 3.7263e-007 -0.312253 0.949999 +vn -0.199687 -0.37713 0.904377 +vn 2.01622e-008 -0.227079 0.973876 +vn 0.274753 0.0248091 0.961195 +vn 0.160503 -0.173398 0.971685 +vn 0.199687 -0.37713 0.904377 +vn -6.29401e-008 0.0937386 -0.995597 +vn -1.92425e-007 -0.048319 -0.998832 +vn 0.0741377 -0.459808 -0.884918 +vn -0.117464 0.0675398 -0.990778 +vn -0.00152237 0.128798 -0.99167 +vn 0.117464 0.0675401 -0.990778 +vn 3.12402e-007 0.421125 -0.907003 +vn -0.242244 0.626065 -0.741189 +vn 0.315312 -0.398044 0.861475 +vn 0.294815 -0.439265 -0.848605 +vn -1.33235e-008 0.275299 -0.961359 +vn 0.154506 0.25498 -0.954522 +vn -0.0741379 -0.459808 -0.884918 +vn -0.294816 -0.439265 -0.848605 +vn -0.154507 0.25498 -0.954522 +vn 5.82132e-008 0.0747053 0.997206 +vn 0.0227405 0.176292 -0.984075 +vn -0.287289 0.157934 -0.944734 +vn -0.681581 -0.590627 -0.431981 +vn -0.288557 0.196748 -0.93703 +vn 0.567433 -0.387695 -0.726438 +vn 0.287439 0.164075 -0.943641 +vn 0.133498 0.140677 -0.981014 +vn 0.141382 0.123811 -0.982182 +vn 0.00996038 0.159002 -0.987228 +vn -2.21061e-006 0.497111 0.867687 +vn 2.0374e-006 0.491748 0.870738 +vn -0.150858 0.549632 0.821673 +vn 0.150864 0.549633 0.821671 +vn 0.496642 0.0754052 0.864674 +vn 0.0459846 0.108957 -0.992982 +vn 0.129541 0.14655 -0.980684 +vn 0.165175 0.054023 -0.984784 +vn 0.160879 0.0769628 -0.983969 +vn 3.0203e-008 0.054314 -0.998524 +vn 0.148337 0.128592 -0.980541 +vn 0.0312878 -0.0449243 -0.9985 +vn 0.0389876 0.0530963 -0.997828 +vn -0.912558 -0.401069 0.0798877 +vn 0.252317 -0.0906853 -0.963386 +vn 0.118789 0.0819611 -0.989531 +vn -0.00913566 -0.263755 0.964546 +vn 0.0548066 -0.19458 0.979354 +vn -0.0210442 -0.200046 0.97956 +vn 3.48353e-006 0.337207 0.94143 +vn -0.0735451 0.486813 0.870405 +vn 0.0735489 0.486815 0.870403 +vn -1.12449e-007 0.0977792 0.995208 +vn -0.149484 0.296662 0.94321 +vn 0.149495 0.296659 0.94321 +vn 0.634138 -0.768521 0.0851172 +vn 0.0115219 -0.318067 -0.947998 +vn 0.0252507 0.0591071 -0.997932 +vn -0.870892 -0.489936 0.0388516 +vn 0.145608 0.076183 -0.986405 +vn -0.339056 -0.12191 -0.932834 +vn -0.588343 -0.126874 -0.798596 +vn -0.941946 -0.14088 -0.304779 +vn -0.995498 0.00742264 -0.0944962 +vn -0.113839 -0.115694 0.98674 +vn -0.230152 0.712626 0.662718 +vn -0.178158 0.946265 0.269892 +vn -0.0168707 -0.575986 0.817286 +vn -0.0207121 0.205228 0.978495 +vn -0.35036 -0.6737 0.650674 +vn -0.921926 -0.354923 -0.155186 +vn -0.61195 -0.351222 -0.708632 +vn -0.862872 -0.477463 -0.165773 +vn -0.830238 -0.555538 -0.0456283 +vn -0.849759 -0.379923 0.36547 +vn -0.96978 -0.243884 0.00691054 +vn -0.55781 0.616393 0.555794 +vn -0.885954 -0.0726422 -0.458048 +vn -0.743451 0.273655 0.61024 +vn -0.480472 0.346483 -0.805665 +vn -0.460163 -0.591877 -0.661764 +vn -0.756644 0.152998 -0.635674 +vn -0.0570279 0.784933 -0.61695 +vn -0.952776 0.122463 -0.277887 +vn -0.496641 0.0754066 0.864674 +vn -0.944225 0.0347314 0.327465 +vn -0.142965 -0.144086 -0.979184 +vn 0.00219889 -0.998356 -0.0572803 +vn -0.0590732 -0.499686 -0.86419 +vn 0.31146 -0.949405 0.0402951 +vn 0.0245033 -0.647892 0.761338 +vn -0.329035 0.803542 -0.496041 +vn -0.316573 0.0717526 -0.94585 +vn -0.448094 0.768089 0.457439 +vn 0.0819548 -0.0690432 0.994242 +vn -0.357563 0.784784 -0.506224 +vn -0.0841981 -0.953427 -0.289635 +vn -0.269005 0.452546 -0.850199 +vn -0.37584 0.858591 -0.348664 +vn -0.225614 0.802381 0.552524 +vn -0.0859554 -0.188469 0.97831 +vn -0.432481 0.723442 0.538138 +vn -0.43652 0.423084 0.794009 +vn -0.484137 0.0561702 -0.873187 +vn -0.836266 0.0839106 -0.541866 +vn -0.454283 0.817035 -0.355079 +vn -0.140921 -0.13076 -0.981348 +vn 0.381529 -0.322465 -0.866286 +vn 0.309632 -0.925876 0.216523 +vn -0.250859 0.942855 -0.219306 +vn -0.158484 0.881393 0.445005 +vn -0.111582 0.944121 -0.310137 +vn -0.224533 0.789658 -0.570985 +vn -0.0791969 0.629759 0.772743 +vn 0.0331107 0.623762 0.780912 +vn -0.0410557 0.864443 0.501051 +vn -0.992817 -0.0954221 0.0721698 +vn -0.973113 -0.163699 -0.162028 +vn -0.88957 -0.189036 -0.415849 +vn -0.910645 -0.22133 0.348911 +vn -0.270144 0.454524 0.848782 +vn -0.0948103 0.788654 -0.607483 +vn 0.668734 -0.237689 -0.704485 +vn -0.386847 0.612378 -0.689451 +vn 0.450466 0.0961704 0.887599 +vn 0.488256 -0.78764 -0.375804 +vn 0.379147 -0.650689 0.657914 +vn -0.733941 -0.399136 0.549565 +vn 0.217765 -0.821826 -0.526479 +vn 0.25531 -0.904369 -0.341956 +vn -0.100122 -0.849368 -0.518218 +vn 0.166113 -0.387329 -0.906853 +vn 0.0168777 -0.962671 0.270149 +vn -0.856861 -0.26656 0.441288 +vn -0.976531 -0.20285 -0.0723845 +vn -0.767434 -0.194841 -0.610805 +vn -0.78551 -0.458369 0.415778 +vn -1.08047e-006 -0.99066 0.136352 +vn -0.989773 0.12776 -0.0634592 +vn -0.0852434 -0.793443 -0.602645 +vn -0.00475357 -0.152499 0.988292 +vn -0.0270633 -0.119041 0.99252 +vn -0.00106533 -0.124052 0.992275 +vn -0.476649 0.392351 0.786681 +vn -0.82408 -0.549593 0.137257 +vn 0.04689 -0.500533 -0.864447 +vn -0.478675 -0.867328 0.136428 +vn 0.0810501 -0.263263 -0.961314 +vn 0.10224 -0.356584 -0.928652 +vn -0.0111046 -0.0850036 0.996319 +vn -0.0270429 -0.0845459 0.996053 +vn -0.00291587 -0.378251 0.925699 +vn -0.823991 0.0112213 0.566492 +vn 0.602088 -0.427261 0.674491 +vn 0.834836 0.278079 -0.475101 +vn 0.73841 -0.449038 0.503105 +vn 0.823991 0.0112215 0.566492 +vn 0.995498 0.00742303 -0.0944963 +vn 0.0672201 0.951229 -0.301072 +vn 0.451214 0.584703 -0.674187 +vn -0.0781496 0.899901 -0.429034 +vn -0.12701 0.888446 -0.441058 +vn 0.926583 0.320374 -0.196989 +vn 0.285316 0.824732 -0.488274 +vn 0.132438 -0.191476 0.972521 +vn 0.557809 0.616395 0.555793 +vn 0.150391 0.899151 0.410986 +vn 0.0240612 -0.584167 0.811277 +vn -0.0203503 -0.655407 0.755001 +vn 0.0390215 0.218137 0.975138 +vn 0.350359 -0.6737 0.650675 +vn 0.921926 -0.354923 -0.155185 +vn 0.849759 -0.379923 0.36547 +vn 0.829473 -0.556768 -0.044555 +vn 0.611951 -0.351222 -0.708632 +vn 0.885955 -0.0726416 -0.458048 +vn 0.96978 -0.243884 0.0069102 +vn 0.862873 -0.477462 -0.165773 +vn 0.460163 -0.591877 -0.661764 +vn 0.484138 0.0561711 -0.873187 +vn 0.74345 0.273659 0.61024 +vn 0.436172 0.63297 -0.639612 +vn 0.407304 0.370933 -0.834573 +vn 0.00586289 0.856092 -0.516791 +vn 0.952776 0.122463 -0.277887 +vn 0.756644 0.152998 -0.635674 +vn 0.186137 -0.184096 -0.965123 +vn 0.322991 0.814766 -0.481491 +vn 0.944225 0.0347319 0.327466 +vn 0.00514322 -0.998366 -0.0569166 +vn -0.313108 -0.949006 0.036755 +vn 0.06819 -0.4932 -0.867239 +vn 0.359422 0.110239 -0.926641 +vn 0.407142 0.67882 -0.611097 +vn 0.448095 0.768089 0.457438 +vn 0.326778 0.798379 0.505773 +vn 0.395529 -0.853999 0.337997 +vn 0.0819485 -0.942961 -0.322659 +vn -0.448028 -0.462224 -0.765258 +vn 0.326416 0.845411 -0.422769 +vn 0.225614 0.802381 0.552524 +vn -0.0790953 -0.0632135 0.994861 +vn 0.588343 -0.126874 -0.798596 +vn 0.941946 -0.140879 -0.304779 +vn 0.0876591 -0.193062 0.977263 +vn 0.459335 0.714462 0.527783 +vn 0.462654 0.799609 -0.382854 +vn 0.836266 0.0839114 -0.541866 +vn 0.129798 -0.134425 -0.982386 +vn -0.381438 -0.322792 -0.866204 +vn -0.25541 -0.904298 -0.342067 +vn -0.309229 -0.926067 0.216278 +vn -0.450463 0.096054 0.887613 +vn 0.250852 0.942855 -0.21931 +vn 0.158545 0.881325 0.445118 +vn 0.111603 0.94428 -0.309646 +vn 0.0411469 0.864217 0.501434 +vn -0.0329505 0.623415 0.781196 +vn 0.0793019 0.6297 0.77278 +vn 0.224331 0.789935 -0.570682 +vn 0.0948954 0.789235 -0.606714 +vn 0.386443 0.613121 -0.689017 +vn 0.973109 -0.163548 -0.162204 +vn 0.992819 -0.0954804 0.0720756 +vn 0.889582 -0.188787 -0.415937 +vn 0.910643 -0.221564 0.348768 +vn 0.270265 0.454095 0.848973 +vn -0.668238 -0.237496 -0.705021 +vn -0.165449 -0.386406 -0.907368 +vn -0.488605 -0.787416 -0.375821 +vn -0.379281 -0.650608 0.657917 +vn 0.0999989 -0.849106 -0.51867 +vn -0.016978 -0.962861 0.269462 +vn 0.733906 -0.399479 0.549362 +vn 0.856862 -0.266561 0.441286 +vn 0.785509 -0.458375 0.415774 +vn 0.976531 -0.202851 -0.0723839 +vn 0.767434 -0.194841 -0.610805 +vn 0.28919 0.129846 -0.948424 +vn 0.0886337 -0.804157 -0.587772 +vn 0.998574 0.0460603 -0.0269857 +vn 0.534395 0.0258967 -0.844838 +vn 0.0615208 -0.0994618 0.993138 +vn -0.0704952 -0.0814869 0.994178 +vn -0.0732202 -0.0932371 0.992948 +vn 0.233166 0.0791844 -0.969208 +vn 0.0122447 -0.244659 0.969532 +vn -0.00584846 -0.174525 0.984635 +vn 0.415006 0.395198 0.819506 +vn 0.70828 -0.682737 0.179469 +vn -0.0431464 -0.5136 -0.856944 +vn -0.112546 -0.245125 -0.962937 +vn -0.0924313 -0.349738 -0.932276 +vn 0.969242 0.218446 0.113361 +vn -0.0756259 -0.0802751 0.9939 +vn -0.0535681 -0.13198 0.989804 +vn 0.0310001 -0.468305 -0.883023 +vn 0.0183109 -0.728603 -0.684691 +vn 0.120727 0.0844533 -0.989087 +vn -0.0590065 -0.199443 0.978131 +vn 0.137775 0.0744078 -0.987665 +vn -0.0598334 -0.156936 0.985795 +vn 0.15148 0.0727224 -0.985781 +vn -0.0659219 -0.125364 0.989918 +vn -0.0520146 -0.121479 0.99123 +vn -0.0752518 -0.10694 0.991414 +vn -0.0571237 -0.110102 0.992277 +vn -0.0689336 -0.0927949 0.993296 +vn -0.0786838 -0.0794667 0.993727 +usemtl archer_arms +g Ar_Ropie_D01_Glove_archer_arms +s 1 +f 361/223/425 399/225/427 365/224/426 +f 361/223/425 401/227/429 362/226/428 +f 362/226/428 398/228/430 361/223/425 +f 362/226/428 403/230/432 363/229/431 +f 362/226/428 404/231/433 403/230/432 +f 363/229/431 368/232/434 362/226/428 +f 363/229/431 369/233/435 368/232/434 +f 363/229/431 402/235/437 364/234/436 +f 363/229/431 403/230/432 402/235/437 +f 364/234/436 369/233/435 363/229/431 +f 364/234/436 370/236/438 369/233/435 +f 364/234/436 400/238/439 365/237/426 +f 364/234/436 402/235/437 400/238/439 +f 365/237/426 370/236/438 364/234/436 +f 365/224/426 399/225/427 366/239/440 +f 365/224/426 400/240/439 361/223/425 +f 366/239/440 370/241/438 365/224/426 +f 366/239/440 371/242/441 370/241/438 +f 366/239/440 372/243/442 371/242/441 +f 366/239/440 398/228/430 367/244/443 +f 366/239/440 399/225/427 398/228/430 +f 367/244/443 372/243/442 366/239/440 +f 367/244/443 373/245/444 372/243/442 +f 367/244/443 398/228/430 368/232/434 +f 368/232/434 373/245/444 367/244/443 +f 368/232/434 374/246/445 373/245/444 +f 368/232/434 398/228/430 362/226/428 +f 369/233/435 374/246/445 368/232/434 +f 369/233/435 380/247/446 374/246/445 +f 370/236/438 380/247/446 369/233/435 +f 371/242/441 375/248/447 370/241/438 +f 371/249/441 379/251/448 375/250/447 +f 372/252/442 376/253/449 371/249/441 +f 372/252/442 377/254/450 376/253/449 +f 373/255/444 377/254/450 372/252/442 +f 373/255/444 378/256/451 377/254/450 +f 374/257/445 378/256/451 373/255/444 +f 374/257/445 382/258/452 378/256/451 +f 374/257/445 383/259/453 382/258/452 +f 375/248/447 380/260/446 370/241/438 +f 375/250/447 381/262/454 380/261/446 +f 376/253/449 379/251/448 371/249/441 +f 376/253/449 391/263/455 379/251/448 +f 376/253/449 392/264/456 391/263/455 +f 377/254/450 392/264/456 376/253/449 +f 377/254/450 393/265/457 392/264/456 +f 378/266/451 385/267/458 381/262/454 +f 378/256/451 393/265/457 377/254/450 +f 379/251/448 381/262/454 375/250/447 +f 379/251/448 390/268/459 381/262/454 +f 379/251/448 391/263/455 390/268/459 +f 380/269/446 383/259/453 374/257/445 +f 380/261/446 384/271/460 383/270/453 +f 381/262/454 384/271/460 380/261/446 +f 381/262/454 385/267/458 384/271/460 +f 381/262/454 393/272/457 378/266/451 +f 382/258/452 385/273/458 378/256/451 +f 382/258/452 386/274/461 385/273/458 +f 383/259/453 386/274/461 382/258/452 +f 383/259/453 387/275/462 386/274/461 +f 383/270/453 388/277/463 387/276/462 +f 384/271/460 388/277/463 383/270/453 +f 384/271/460 389/278/464 388/277/463 +f 385/267/458 389/278/464 384/271/460 +f 386/274/461 389/279/464 385/273/458 +f 387/275/462 388/280/463 386/274/461 +f 388/280/463 389/279/464 386/274/461 +f 390/268/459 393/272/457 381/262/454 +f 390/268/459 394/281/465 393/272/457 +f 390/268/459 395/282/466 394/281/465 +f 391/263/455 395/282/466 390/268/459 +f 391/263/455 396/283/467 395/282/466 +f 392/264/456 396/283/467 391/263/455 +f 392/264/456 397/284/468 396/283/467 +f 393/265/457 397/284/468 392/264/456 +f 394/281/465 397/285/468 393/272/457 +f 395/282/466 396/283/467 394/281/465 +f 396/283/467 397/284/468 394/281/465 +f 398/228/430 399/225/427 361/223/425 +f 400/240/439 401/227/429 361/223/425 +f 400/240/439 405/286/469 401/227/429 +f 400/238/439 407/288/470 405/287/469 +f 401/227/429 404/231/433 362/226/428 +f 401/227/429 406/289/471 404/231/433 +f 402/235/437 407/288/470 400/238/439 +f 402/235/437 408/290/472 407/288/470 +f 403/230/432 408/290/472 402/235/437 +f 403/230/432 409/291/473 408/290/472 +f 404/231/433 409/291/473 403/230/432 +f 405/286/469 406/289/471 401/227/429 +f 405/292/469 410/294/474 406/293/471 +f 406/289/471 409/291/473 404/231/433 +f 406/293/471 410/294/474 409/295/473 +f 407/296/470 410/294/474 405/292/469 +f 408/297/472 410/294/474 407/296/470 +f 409/295/473 410/294/474 408/297/472 +f 411/223/475 448/228/477 412/226/476 +f 411/223/475 449/225/478 448/228/477 +f 411/223/475 450/240/480 415/224/479 +f 411/223/475 451/227/481 450/240/480 +f 412/226/476 418/232/483 413/229/482 +f 412/226/476 448/228/477 418/232/483 +f 412/226/476 451/227/481 411/223/475 +f 412/226/476 454/231/484 451/227/481 +f 413/229/482 419/233/486 414/234/485 +f 413/229/482 453/230/487 412/226/476 +f 414/234/485 420/236/488 415/237/479 +f 414/234/485 452/235/489 413/229/482 +f 415/224/479 420/241/488 416/239/490 +f 415/224/479 449/225/478 411/223/475 +f 415/237/479 450/238/480 414/234/485 +f 416/239/490 422/243/492 417/244/491 +f 416/239/490 449/225/478 415/224/479 +f 417/244/491 423/245/493 418/232/483 +f 417/244/491 448/228/477 416/239/490 +f 418/232/483 419/233/486 413/229/482 +f 418/232/483 424/246/494 419/233/486 +f 418/232/483 448/228/477 417/244/491 +f 419/233/486 420/236/488 414/234/485 +f 419/233/486 430/247/495 420/236/488 +f 420/241/488 421/242/496 416/239/490 +f 420/241/488 425/248/497 421/242/496 +f 420/241/488 430/260/495 425/248/497 +f 421/242/496 422/243/492 416/239/490 +f 421/249/496 426/253/498 422/252/492 +f 421/249/496 429/251/499 426/253/498 +f 422/243/492 423/245/493 417/244/491 +f 422/252/492 427/254/500 423/255/493 +f 423/245/493 424/246/494 418/232/483 +f 423/255/493 428/256/501 424/257/494 +f 424/246/494 430/247/495 419/233/486 +f 424/257/494 433/259/502 430/269/495 +f 425/250/497 429/251/499 421/249/496 +f 425/250/497 431/262/503 429/251/499 +f 426/253/498 427/254/500 422/252/492 +f 426/253/498 442/264/504 427/254/500 +f 427/254/500 428/256/501 423/255/493 +f 427/254/500 443/265/505 428/256/501 +f 428/256/501 432/258/506 424/257/494 +f 428/256/501 435/273/507 432/258/506 +f 428/266/501 443/272/505 431/262/503 +f 429/251/499 441/263/508 426/253/498 +f 430/261/495 431/262/503 425/250/497 +f 430/261/495 434/271/509 431/262/503 +f 431/262/503 435/267/507 428/266/501 +f 431/262/503 440/268/510 429/251/499 +f 431/262/503 443/272/505 440/268/510 +f 432/258/506 433/259/502 424/257/494 +f 432/258/506 436/274/511 433/259/502 +f 433/270/502 434/271/509 430/261/495 +f 433/270/502 438/277/512 434/271/509 +f 434/271/509 435/267/507 431/262/503 +f 434/271/509 439/278/513 435/267/507 +f 435/273/507 436/274/511 432/258/506 +f 435/273/507 439/279/513 436/274/511 +f 436/274/511 437/275/514 433/259/502 +f 436/274/511 438/280/512 437/275/514 +f 436/274/511 439/279/513 438/280/512 +f 437/276/514 438/277/512 433/270/502 +f 438/277/512 439/278/513 434/271/509 +f 440/268/510 441/263/508 429/251/499 +f 440/268/510 445/282/515 441/263/508 +f 441/263/508 442/264/504 426/253/498 +f 441/263/508 446/283/516 442/264/504 +f 442/264/504 443/265/505 427/254/500 +f 442/264/504 447/284/517 443/265/505 +f 443/272/505 444/281/518 440/268/510 +f 443/272/505 447/285/517 444/281/518 +f 444/281/518 445/282/515 440/268/510 +f 444/281/518 446/283/516 445/282/515 +f 444/281/518 447/284/517 446/283/516 +f 445/282/515 446/283/516 441/263/508 +f 446/283/516 447/284/517 442/264/504 +f 448/228/477 449/225/478 416/239/490 +f 450/238/480 452/235/489 414/234/485 +f 450/238/480 457/288/519 452/235/489 +f 451/227/481 455/286/520 450/240/480 +f 451/227/481 456/289/521 455/286/520 +f 452/235/489 453/230/487 413/229/482 +f 452/235/489 458/290/522 453/230/487 +f 453/230/487 454/231/484 412/226/476 +f 453/230/487 459/291/523 454/231/484 +f 454/231/484 456/289/521 451/227/481 +f 454/231/484 459/291/523 456/289/521 +f 455/287/520 457/288/519 450/238/480 +f 455/292/520 460/294/524 457/296/519 +f 456/293/521 460/294/524 455/292/520 +f 457/288/519 458/290/522 452/235/489 +f 457/296/519 460/294/524 458/297/522 +f 458/290/522 459/291/523 453/230/487 +f 458/297/522 460/294/524 459/295/523 +f 459/295/523 460/294/524 456/293/521 +usemtl archer_body +g Ar_Ropie_D01_Body_archer_body +s 1 +f 936/672/1033 1063/674/1035 940/673/1034 +f 936/672/1033 1072/673/1036 1063/674/1035 +f 937/675/1037 945/677/1039 939/676/1038 +f 937/675/1037 1071/676/1040 945/677/1039 +f 938/678/1041 998/680/1042 939/679/1038 +f 939/676/1038 940/682/1034 938/681/1041 +f 939/676/1038 945/677/1039 940/682/1034 +f 939/679/1038 954/684/1043 937/683/1037 +f 939/679/1038 998/680/1042 954/684/1043 +f 940/682/1034 941/685/1044 938/681/1041 +f 940/682/1034 943/686/1045 941/685/1044 +f 940/682/1034 945/677/1039 936/687/1033 +f 940/682/1034 1067/688/1046 943/686/1045 +f 941/689/1044 997/690/1047 938/678/1041 +f 942/691/1048 973/693/1050 944/692/1049 +f 942/691/1048 977/694/1051 973/693/1050 +f 942/691/1048 979/695/1052 977/694/1051 +f 942/691/1048 1067/697/1046 978/696/1053 +f 943/698/1045 997/690/1047 941/689/1044 +f 943/686/1045 1067/688/1046 944/699/1049 +f 943/698/1045 1069/700/1054 997/690/1047 +f 944/699/1049 1067/688/1046 942/701/1048 +f 944/692/1049 1069/700/1054 943/698/1045 +f 945/677/1039 1072/682/1036 936/687/1033 +f 946/702/1055 978/696/1053 966/703/1056 +f 946/702/1055 1089/696/1058 949/704/1057 +f 946/702/1055 1106/705/1060 1077/703/1059 +f 947/706/1061 972/708/1063 969/707/1062 +f 947/706/1061 983/710/1065 953/709/1064 +f 947/706/1061 1083/708/1067 950/711/1066 +f 947/706/1061 1094/710/1069 1080/707/1068 +f 948/712/1070 981/714/1072 951/713/1071 +f 948/712/1070 1004/715/1073 981/714/1072 +f 948/712/1070 1115/715/1075 959/716/1074 +f 949/704/1057 978/696/1053 946/702/1055 +f 949/704/1057 979/695/1052 978/696/1053 +f 949/704/1057 1090/695/1077 952/717/1076 +f 950/711/1066 972/708/1063 947/706/1061 +f 950/711/1066 998/680/1042 972/708/1063 +f 950/711/1066 1109/680/1078 954/684/1043 +f 951/713/1071 981/714/1072 980/718/1079 +f 951/713/1071 1001/720/1081 955/719/1080 +f 951/713/1071 1092/714/1082 948/712/1070 +f 951/713/1071 1112/720/1084 1091/718/1083 +f 952/717/1076 979/695/1052 949/704/1057 +f 952/717/1076 1090/695/1077 955/719/1080 +f 953/709/1064 983/710/1065 958/721/1085 +f 953/709/1064 1094/710/1069 947/706/1061 +f 954/684/1043 998/680/1042 950/711/1066 +f 954/684/1043 1071/679/1040 937/683/1037 +f 954/684/1043 1109/680/1078 1071/679/1040 +f 955/719/1080 979/695/1052 952/717/1076 +f 955/719/1080 1001/720/1081 979/695/1052 +f 955/719/1080 1112/720/1084 951/713/1071 +f 956/722/1086 1042/723/1087 959/716/1074 +f 956/722/1086 1052/725/1089 1039/724/1088 +f 956/722/1086 1153/723/1091 1150/724/1090 +f 956/722/1086 1204/727/1093 1228/726/1092 +f 956/722/1086 1228/726/1092 1203/728/1094 +f 957/729/1095 1041/731/1097 962/730/1096 +f 957/729/1095 1152/731/1098 958/721/1085 +f 958/721/1085 1041/731/1097 957/729/1095 +f 958/721/1085 1094/710/1069 953/709/1064 +f 958/721/1085 1142/732/1099 1094/710/1069 +f 958/721/1085 1152/731/1098 1142/732/1099 +f 959/716/1074 1004/715/1073 948/712/1070 +f 959/716/1074 1042/723/1087 1004/715/1073 +f 959/716/1074 1153/723/1091 956/722/1086 +f 960/733/1100 1203/728/1094 1228/726/1092 +f 960/733/1100 1228/726/1092 1207/734/1101 +f 960/733/1100 1206/736/1103 1226/735/1102 +f 960/733/1100 1226/735/1102 1205/737/1104 +f 960/733/1100 1207/734/1101 1225/738/1105 +f 960/733/1100 1225/738/1105 1206/736/1103 +f 961/739/1106 1048/741/1108 1208/740/1107 +f 961/739/1106 1210/743/1110 1230/742/1109 +f 961/739/1106 1230/742/1109 1209/744/1111 +f 961/745/1106 1211/747/1113 1044/746/1112 +f 962/730/1096 1055/749/1115 963/748/1114 +f 962/730/1096 1152/731/1098 957/729/1095 +f 962/730/1096 1166/749/1116 1152/731/1098 +f 963/748/1114 1056/751/1118 964/750/1117 +f 963/748/1114 1166/749/1116 962/730/1096 +f 963/748/1114 1167/751/1119 1166/749/1116 +f 964/750/1117 1167/751/1119 963/748/1114 +f 964/750/1117 1168/752/1120 1167/751/1119 +f 964/753/1117 1187/755/1121 1168/754/1120 +f 965/756/1122 1048/741/1108 1043/757/1123 +f 965/756/1122 1205/737/1104 1226/735/1102 +f 965/756/1122 1226/735/1102 1212/758/1124 +f 965/756/1122 1208/740/1107 1048/741/1108 +f 966/703/1056 995/705/1125 946/702/1055 +f 966/703/1056 996/759/1126 995/705/1125 +f 966/703/1056 1065/760/1127 996/759/1126 +f 966/703/1056 1066/761/1128 1065/760/1127 +f 966/703/1056 1067/697/1046 1066/761/1128 +f 967/762/1129 994/764/1131 988/763/1130 +f 967/762/1129 1060/766/1133 989/765/1132 +f 967/767/1129 1061/768/1134 969/707/1062 +f 968/769/1135 974/771/1137 970/770/1136 +f 968/769/1135 984/772/1138 974/771/1137 +f 968/769/1135 1007/774/1140 982/773/1139 +f 969/707/1062 971/775/1141 967/767/1129 +f 969/707/1062 972/708/1063 971/775/1141 +f 969/707/1062 983/710/1065 947/706/1061 +f 969/707/1062 1061/768/1134 983/710/1065 +f 970/770/1136 1006/776/1142 968/769/1135 +f 971/777/1141 994/764/1131 967/762/1129 +f 971/775/1141 1069/700/1054 973/693/1050 +f 972/708/1063 1068/778/1143 971/775/1141 +f 973/693/1050 977/694/1051 976/779/1144 +f 973/780/1050 994/764/1131 971/777/1141 +f 973/693/1050 1069/700/1054 944/692/1049 +f 974/771/1137 975/781/1145 970/770/1136 +f 974/771/1137 1000/782/1146 975/781/1145 +f 975/781/1145 981/714/1072 970/770/1136 +f 975/781/1145 1001/720/1081 980/718/1079 +f 976/783/1144 993/784/1147 973/780/1050 +f 976/779/1144 999/785/1148 984/772/1138 +f 977/694/1051 999/785/1148 976/779/1144 +f 977/694/1051 1000/782/1146 999/785/1148 +f 977/694/1051 1001/720/1081 1000/782/1146 +f 978/696/1053 979/695/1052 942/691/1048 +f 978/696/1053 1067/697/1046 966/703/1056 +f 979/695/1052 1001/720/1081 977/694/1051 +f 980/718/1079 981/714/1072 975/781/1145 +f 980/718/1079 1001/720/1081 951/713/1071 +f 981/714/1072 1004/715/1073 970/770/1136 +f 982/773/1139 984/772/1138 968/769/1135 +f 982/773/1139 1031/732/1149 983/710/1065 +f 982/773/1139 1032/786/1150 1031/732/1149 +f 982/773/1139 1061/768/1134 984/772/1138 +f 983/710/1065 1031/732/1149 958/721/1085 +f 983/710/1065 1061/768/1134 982/773/1139 +f 984/787/1138 986/789/1151 976/788/1144 +f 984/772/1138 999/785/1148 974/771/1137 +f 984/787/1138 1061/791/1134 985/790/1152 +f 985/790/1152 986/789/1151 984/787/1138 +f 985/790/1152 1058/792/1153 986/789/1151 +f 985/790/1152 1059/794/1155 1034/793/1154 +f 985/790/1152 1061/791/1134 1059/794/1155 +f 986/795/1151 990/797/1157 987/796/1156 +f 986/795/1151 993/784/1147 976/783/1144 +f 986/789/1151 1058/792/1153 990/798/1157 +f 987/796/1156 992/799/1158 988/763/1130 +f 987/796/1156 993/784/1147 986/795/1151 +f 987/796/1156 994/764/1131 993/784/1147 +f 988/763/1130 994/764/1131 987/796/1156 +f 988/763/1130 1060/766/1133 967/762/1129 +f 989/800/1132 1059/794/1155 967/801/1129 +f 989/765/1132 1060/766/1133 1030/802/1159 +f 990/797/1157 991/803/1160 987/796/1156 +f 990/798/1157 1058/792/1153 1008/804/1161 +f 990/797/1157 1062/805/1162 991/803/1160 +f 991/803/1160 992/799/1158 987/796/1156 +f 991/803/1160 1019/806/1163 992/799/1158 +f 991/803/1160 1062/805/1162 1019/806/1163 +f 992/799/1158 1019/806/1163 1018/807/1164 +f 992/799/1158 1060/766/1133 988/763/1130 +f 993/784/1147 994/764/1131 973/780/1050 +f 997/690/1047 998/680/1042 938/678/1041 +f 997/690/1047 1068/778/1143 998/680/1042 +f 997/690/1047 1069/700/1054 1068/778/1143 +f 998/680/1042 1068/778/1143 972/708/1063 +f 999/785/1148 1000/782/1146 974/771/1137 +f 1000/782/1146 1001/720/1081 975/781/1145 +f 1002/808/1165 1009/810/1167 1003/809/1166 +f 1002/808/1165 1059/794/1155 1009/810/1167 +f 1004/715/1073 1005/811/1168 970/770/1136 +f 1004/715/1073 1042/723/1087 1005/811/1168 +f 1005/811/1168 1006/776/1142 970/770/1136 +f 1005/811/1168 1033/812/1169 1006/776/1142 +f 1005/811/1168 1042/723/1087 1033/812/1169 +f 1006/776/1142 1007/774/1140 968/769/1135 +f 1006/776/1142 1033/812/1169 1007/774/1140 +f 1007/774/1140 1032/786/1150 982/773/1139 +f 1007/774/1140 1033/812/1169 1032/786/1150 +f 1008/804/1161 1036/814/1170 1009/813/1167 +f 1008/804/1161 1058/792/1153 1035/815/1171 +f 1008/816/1161 1062/818/1162 990/817/1157 +f 1008/816/1161 1183/820/1173 1021/819/1172 +f 1009/813/1167 1036/814/1170 1003/821/1166 +f 1009/810/1167 1059/794/1155 989/800/1132 +f 1010/822/1174 1012/824/1176 1011/823/1175 +f 1010/822/1174 1014/825/1177 1012/824/1176 +f 1010/822/1174 1019/806/1163 1014/825/1177 +f 1011/823/1175 1017/827/1179 1016/826/1178 +f 1011/823/1175 1018/807/1164 1010/822/1174 +f 1012/824/1176 1013/828/1180 1011/823/1175 +f 1012/824/1176 1049/829/1181 1013/828/1180 +f 1012/824/1176 1051/831/1183 1026/830/1182 +f 1013/828/1180 1017/827/1179 1011/823/1175 +f 1013/828/1180 1049/829/1181 1029/832/1184 +f 1013/828/1180 1050/833/1185 1017/827/1179 +f 1014/825/1177 1015/834/1186 1012/824/1176 +f 1014/825/1177 1023/835/1187 1015/834/1186 +f 1015/834/1186 1028/836/1188 1012/824/1176 +f 1016/826/1178 1018/807/1164 1011/823/1175 +f 1016/826/1178 1020/837/1189 1018/807/1164 +f 1017/827/1179 1020/837/1189 1016/826/1178 +f 1017/827/1179 1022/838/1190 1020/837/1189 +f 1017/827/1179 1024/839/1191 1022/838/1190 +f 1017/827/1179 1027/840/1192 1024/839/1191 +f 1017/827/1179 1050/833/1185 1027/840/1192 +f 1018/807/1164 1019/806/1163 1010/822/1174 +f 1018/807/1164 1030/802/1159 992/799/1158 +f 1019/806/1163 1021/841/1172 1014/825/1177 +f 1019/806/1163 1062/805/1162 1021/841/1172 +f 1020/837/1189 1030/802/1159 1018/807/1164 +f 1020/842/1189 1180/844/1193 1030/843/1159 +f 1020/842/1189 1181/845/1194 1180/844/1193 +f 1021/841/1172 1023/835/1187 1014/825/1177 +f 1021/819/1172 1062/818/1162 1008/816/1161 +f 1021/819/1172 1183/820/1173 1023/846/1187 +f 1022/847/1190 1181/845/1194 1020/842/1189 +f 1022/847/1190 1182/848/1195 1181/845/1194 +f 1023/835/1187 1025/849/1196 1015/834/1186 +f 1023/846/1187 1184/851/1197 1025/850/1196 +f 1024/852/1191 1182/848/1195 1022/847/1190 +f 1025/849/1196 1028/836/1188 1015/834/1186 +f 1025/850/1196 1184/851/1197 1028/853/1188 +f 1026/830/1182 1049/829/1181 1012/824/1176 +f 1026/854/1182 1184/851/1197 1049/855/1181 +f 1027/856/1192 1182/848/1195 1024/852/1191 +f 1028/836/1188 1051/831/1183 1012/824/1176 +f 1028/853/1188 1184/851/1197 1051/857/1183 +f 1029/832/1184 1050/833/1185 1013/828/1180 +f 1029/858/1184 1182/848/1195 1050/859/1185 +f 1030/802/1159 1060/766/1133 992/799/1158 +f 1030/843/1159 1180/844/1193 989/860/1132 +f 1031/732/1149 1041/731/1097 958/721/1085 +f 1032/786/1150 1037/861/1198 1031/732/1149 +f 1032/786/1150 1038/862/1199 1037/861/1198 +f 1033/812/1169 1038/862/1199 1032/786/1150 +f 1033/812/1169 1053/863/1200 1038/862/1199 +f 1034/793/1154 1058/792/1153 985/790/1152 +f 1034/793/1154 1059/794/1155 1002/808/1165 +f 1035/815/1171 1036/814/1170 1008/804/1161 +f 1035/815/1171 1058/792/1153 1034/793/1154 +f 1037/861/1198 1040/864/1201 1031/732/1149 +f 1037/865/1198 1195/867/1202 1040/866/1201 +f 1038/868/1199 1195/870/1202 1037/869/1198 +f 1039/724/1088 1042/723/1087 956/722/1086 +f 1039/724/1088 1053/863/1200 1042/723/1087 +f 1039/871/1088 1195/870/1202 1053/872/1200 +f 1040/864/1201 1041/731/1097 1031/732/1149 +f 1040/864/1201 1054/873/1203 1041/731/1097 +f 1040/866/1201 1192/875/1204 1054/874/1203 +f 1040/866/1201 1195/867/1202 1192/875/1204 +f 1041/731/1097 1055/749/1115 962/730/1096 +f 1042/723/1087 1053/863/1200 1033/812/1169 +f 1043/757/1123 1052/725/1089 960/733/1100 +f 1043/876/1123 1185/878/1205 1052/877/1089 +f 1043/757/1123 1205/737/1104 965/756/1122 +f 1043/876/1123 1223/879/1206 1185/878/1205 +f 1044/880/1112 1048/741/1108 961/739/1106 +f 1044/746/1112 1191/882/1207 1048/881/1108 +f 1044/746/1112 1211/747/1113 1191/882/1207 +f 1045/883/1208 1055/749/1115 1054/873/1203 +f 1045/883/1208 1056/751/1118 1055/749/1115 +f 1045/884/1208 1193/886/1210 1046/885/1209 +f 1046/887/1209 1056/751/1118 1045/883/1208 +f 1046/887/1209 1057/752/1211 1056/751/1118 +f 1046/885/1209 1194/889/1213 1047/888/1212 +f 1047/890/1212 1057/752/1211 1046/887/1209 +f 1047/888/1212 1194/889/1213 1057/754/1211 +f 1048/881/1108 1186/891/1214 1043/876/1123 +f 1048/881/1108 1224/892/1215 1186/891/1214 +f 1049/855/1181 1182/848/1195 1029/858/1184 +f 1049/855/1181 1184/851/1197 1182/848/1195 +f 1050/859/1185 1182/848/1195 1027/856/1192 +f 1051/857/1183 1184/851/1197 1026/854/1182 +f 1052/877/1089 1190/893/1216 1039/871/1088 +f 1052/725/1089 1203/728/1094 960/733/1100 +f 1053/872/1200 1195/870/1202 1038/868/1199 +f 1054/873/1203 1055/749/1115 1041/731/1097 +f 1054/874/1203 1193/886/1210 1045/884/1208 +f 1055/749/1115 1056/751/1118 963/748/1114 +f 1056/751/1118 1057/752/1211 964/750/1117 +f 1057/754/1211 1187/755/1121 964/753/1117 +f 1057/754/1211 1194/889/1213 1187/755/1121 +f 1059/794/1155 1061/791/1134 967/801/1129 +f 1063/674/1035 1064/894/1217 940/673/1034 +f 1064/894/1217 1066/761/1128 940/673/1034 +f 1065/760/1127 1066/761/1128 1064/894/1217 +f 1066/761/1128 1067/697/1046 940/673/1034 +f 1068/778/1143 1069/700/1054 971/775/1141 +f 1070/681/1218 1072/682/1036 1071/676/1040 +f 1070/681/1218 1073/685/1219 1072/682/1036 +f 1070/678/1218 1108/690/1220 1073/689/1219 +f 1070/678/1218 1109/680/1078 1108/690/1220 +f 1071/676/1040 1072/682/1036 945/677/1039 +f 1071/679/1040 1109/680/1078 1070/678/1218 +f 1072/673/1036 1174/894/1221 1063/674/1035 +f 1072/673/1036 1176/761/1222 1174/894/1221 +f 1072/673/1036 1177/697/1223 1176/761/1222 +f 1073/685/1219 1075/686/1224 1072/682/1036 +f 1073/689/1219 1108/690/1220 1075/698/1224 +f 1074/691/1225 1090/695/1077 1089/696/1058 +f 1074/701/1225 1177/688/1223 1076/699/1226 +f 1075/686/1224 1177/688/1223 1072/682/1036 +f 1075/698/1224 1179/700/1227 1076/692/1226 +f 1076/692/1226 1084/693/1228 1074/691/1225 +f 1076/699/1226 1177/688/1223 1075/686/1224 +f 1076/692/1226 1179/700/1227 1084/693/1228 +f 1077/703/1059 1089/696/1058 946/702/1055 +f 1077/703/1059 1177/697/1223 1089/696/1058 +f 1078/767/1229 1082/775/1230 1080/707/1068 +f 1078/762/1229 1105/764/1231 1082/777/1230 +f 1078/801/1229 1170/794/1233 1100/800/1232 +f 1078/762/1229 1171/766/1234 1105/764/1231 +f 1078/801/1229 1172/791/1235 1170/794/1233 +f 1079/769/1236 1095/772/1238 1093/773/1237 +f 1079/769/1236 1117/776/1240 1081/770/1239 +f 1079/769/1236 1118/774/1241 1117/776/1240 +f 1080/707/1068 1083/708/1067 947/706/1061 +f 1080/707/1068 1172/768/1235 1078/767/1229 +f 1081/770/1239 1085/771/1242 1079/769/1236 +f 1081/770/1239 1086/781/1243 1085/771/1242 +f 1081/770/1239 1092/714/1082 1086/781/1243 +f 1081/770/1239 1115/715/1075 1092/714/1082 +f 1081/770/1239 1116/811/1244 1115/715/1075 +f 1081/770/1239 1117/776/1240 1116/811/1244 +f 1082/775/1230 1083/708/1067 1080/707/1068 +f 1082/777/1230 1105/764/1231 1084/780/1228 +f 1082/775/1230 1178/778/1245 1083/708/1067 +f 1082/775/1230 1179/700/1227 1178/778/1245 +f 1083/708/1067 1109/680/1078 950/711/1066 +f 1083/708/1067 1178/778/1245 1109/680/1078 +f 1084/693/1228 1088/694/1246 1074/691/1225 +f 1084/780/1228 1104/784/1248 1087/783/1247 +f 1084/780/1228 1105/764/1231 1104/784/1248 +f 1084/693/1228 1179/700/1227 1082/775/1230 +f 1085/771/1242 1095/772/1238 1079/769/1236 +f 1085/771/1242 1110/785/1249 1095/772/1238 +f 1085/771/1242 1111/782/1250 1110/785/1249 +f 1086/781/1243 1092/714/1082 1091/718/1083 +f 1086/781/1243 1111/782/1250 1085/771/1242 +f 1086/781/1243 1112/720/1084 1111/782/1250 +f 1087/779/1247 1088/694/1246 1084/693/1228 +f 1087/788/1247 1097/789/1251 1095/787/1238 +f 1087/783/1247 1098/796/1252 1097/795/1251 +f 1087/783/1247 1104/784/1248 1098/796/1252 +f 1087/779/1247 1110/785/1249 1088/694/1246 +f 1088/694/1246 1090/695/1077 1074/691/1225 +f 1088/694/1246 1112/720/1084 1090/695/1077 +f 1089/696/1058 1090/695/1077 949/704/1057 +f 1089/696/1058 1177/697/1223 1074/691/1225 +f 1090/695/1077 1112/720/1084 955/719/1080 +f 1091/718/1083 1092/714/1082 951/713/1071 +f 1091/718/1083 1112/720/1084 1086/781/1243 +f 1092/714/1082 1115/715/1075 948/712/1070 +f 1093/773/1237 1118/774/1241 1079/769/1236 +f 1093/773/1237 1143/786/1253 1118/774/1241 +f 1093/773/1237 1172/768/1235 1094/710/1069 +f 1094/710/1069 1142/732/1099 1093/773/1237 +f 1094/710/1069 1172/768/1235 1080/707/1068 +f 1095/787/1238 1097/789/1251 1096/790/1254 +f 1095/772/1238 1110/785/1249 1087/779/1247 +f 1095/772/1238 1172/768/1235 1093/773/1237 +f 1096/790/1254 1169/792/1256 1145/793/1255 +f 1096/790/1254 1172/791/1235 1095/787/1238 +f 1097/795/1251 1102/803/1258 1101/797/1257 +f 1097/789/1251 1169/792/1256 1096/790/1254 +f 1098/796/1252 1102/803/1258 1097/795/1251 +f 1098/796/1252 1103/799/1259 1102/803/1258 +f 1098/796/1252 1105/764/1231 1099/763/1260 +f 1099/763/1260 1103/799/1259 1098/796/1252 +f 1099/763/1260 1171/766/1234 1103/799/1259 +f 1100/800/1232 1170/794/1233 1120/810/1261 +f 1100/765/1232 1171/766/1234 1078/762/1229 +f 1101/798/1257 1169/792/1256 1097/789/1251 +f 1101/817/1257 1173/818/1263 1119/816/1262 +f 1102/803/1258 1130/806/1264 1101/797/1257 +f 1103/799/1259 1130/806/1264 1102/803/1258 +f 1103/799/1259 1141/802/1266 1129/807/1265 +f 1103/799/1259 1171/766/1234 1141/802/1266 +f 1104/784/1248 1105/764/1231 1098/796/1252 +f 1105/764/1231 1171/766/1234 1099/763/1260 +f 1106/705/1060 1107/759/1267 1077/703/1059 +f 1107/759/1267 1175/760/1268 1077/703/1059 +f 1108/690/1220 1179/700/1227 1075/698/1224 +f 1109/680/1078 1178/778/1245 1108/690/1220 +f 1110/785/1249 1111/782/1250 1088/694/1246 +f 1111/782/1250 1112/720/1084 1088/694/1246 +f 1113/808/1269 1170/794/1233 1145/793/1255 +f 1114/809/1270 1120/810/1261 1113/808/1269 +f 1114/821/1270 1147/814/1271 1120/813/1261 +f 1115/715/1075 1153/723/1091 959/716/1074 +f 1116/811/1244 1153/723/1091 1115/715/1075 +f 1117/776/1240 1144/812/1272 1116/811/1244 +f 1118/774/1241 1144/812/1272 1117/776/1240 +f 1119/804/1262 1147/814/1271 1146/815/1273 +f 1119/804/1262 1169/792/1256 1101/798/1257 +f 1119/816/1262 1173/818/1263 1132/819/1274 +f 1119/816/1262 1196/845/1275 1120/844/1261 +f 1119/816/1262 1198/820/1276 1196/845/1275 +f 1120/844/1261 1141/843/1266 1100/860/1232 +f 1120/813/1261 1147/814/1271 1119/804/1262 +f 1120/810/1261 1170/794/1233 1113/808/1269 +f 1120/844/1261 1196/845/1275 1131/842/1277 +f 1121/822/1278 1129/807/1265 1122/823/1279 +f 1121/822/1278 1130/806/1264 1129/807/1265 +f 1122/823/1279 1123/824/1280 1121/822/1278 +f 1122/823/1279 1124/828/1281 1123/824/1280 +f 1122/823/1279 1128/827/1282 1124/828/1281 +f 1122/823/1279 1129/807/1265 1127/826/1283 +f 1123/824/1280 1125/825/1284 1121/822/1278 +f 1123/824/1280 1126/834/1285 1125/825/1284 +f 1123/824/1280 1139/836/1286 1126/834/1285 +f 1123/824/1280 1160/829/1288 1137/830/1287 +f 1123/824/1280 1162/831/1289 1139/836/1286 +f 1124/828/1281 1160/829/1288 1123/824/1280 +f 1124/828/1281 1161/833/1291 1140/832/1290 +f 1125/825/1284 1130/806/1264 1121/822/1278 +f 1125/825/1284 1132/841/1274 1130/806/1264 +f 1125/825/1284 1134/835/1292 1132/841/1274 +f 1126/834/1285 1134/835/1292 1125/825/1284 +f 1126/834/1285 1136/849/1293 1134/835/1292 +f 1126/834/1285 1139/836/1286 1136/849/1293 +f 1127/826/1283 1128/827/1282 1122/823/1279 +f 1127/826/1283 1131/837/1277 1128/827/1282 +f 1128/827/1282 1161/833/1291 1124/828/1281 +f 1129/807/1265 1130/806/1264 1103/799/1259 +f 1129/807/1265 1131/837/1277 1127/826/1283 +f 1129/807/1265 1141/802/1266 1131/837/1277 +f 1130/806/1264 1173/805/1263 1101/797/1257 +f 1131/837/1277 1133/838/1294 1128/827/1282 +f 1131/842/1277 1141/843/1266 1120/844/1261 +f 1131/842/1277 1196/845/1275 1133/847/1294 +f 1132/841/1274 1173/805/1263 1130/806/1264 +f 1132/819/1274 1198/820/1276 1119/816/1262 +f 1133/838/1294 1135/839/1295 1128/827/1282 +f 1133/847/1294 1197/848/1296 1135/852/1295 +f 1134/846/1292 1198/820/1276 1132/819/1274 +f 1134/846/1292 1199/851/1297 1198/820/1276 +f 1135/839/1295 1138/840/1298 1128/827/1282 +f 1135/852/1295 1197/848/1296 1138/856/1298 +f 1136/850/1293 1199/851/1297 1134/846/1292 +f 1137/830/1287 1162/831/1289 1123/824/1280 +f 1137/854/1287 1199/851/1297 1162/857/1289 +f 1138/840/1298 1161/833/1291 1128/827/1282 +f 1138/856/1298 1197/848/1296 1161/859/1291 +f 1139/853/1286 1199/851/1297 1136/850/1293 +f 1140/832/1290 1160/829/1288 1124/828/1281 +f 1140/858/1290 1197/848/1296 1160/855/1288 +f 1141/802/1266 1171/766/1234 1100/765/1232 +f 1142/732/1099 1143/786/1253 1093/773/1237 +f 1142/732/1099 1148/861/1299 1143/786/1253 +f 1142/732/1099 1151/864/1300 1148/861/1299 +f 1142/732/1099 1152/731/1098 1151/864/1300 +f 1143/786/1253 1144/812/1272 1118/774/1241 +f 1143/786/1253 1149/862/1301 1144/812/1272 +f 1144/812/1272 1153/723/1091 1116/811/1244 +f 1144/812/1272 1164/863/1302 1153/723/1091 +f 1145/793/1255 1169/792/1256 1146/815/1273 +f 1145/793/1255 1170/794/1233 1096/790/1254 +f 1146/815/1273 1169/792/1256 1119/804/1262 +f 1148/861/1299 1149/862/1301 1143/786/1253 +f 1148/869/1299 1195/870/1202 1149/868/1301 +f 1149/862/1301 1164/863/1302 1144/812/1272 +f 1149/868/1301 1195/870/1202 1164/872/1302 +f 1150/871/1090 1190/893/1216 1163/877/1303 +f 1150/871/1090 1195/870/1202 1190/893/1216 +f 1150/724/1090 1204/727/1093 956/722/1086 +f 1151/866/1300 1195/867/1202 1148/865/1299 +f 1151/866/1300 1200/875/1304 1195/867/1202 +f 1152/731/1098 1165/873/1305 1151/864/1300 +f 1152/731/1098 1166/749/1116 1165/873/1305 +f 1153/723/1091 1164/863/1302 1150/724/1090 +f 1154/757/1306 1206/736/1103 1225/738/1105 +f 1154/757/1306 1225/738/1105 1215/895/1307 +f 1154/757/1306 1212/758/1124 1226/735/1102 +f 1154/757/1306 1226/735/1102 1206/736/1103 +f 1154/876/1306 1217/897/1309 1234/896/1308 +f 1154/876/1306 1234/896/1308 1214/898/1310 +f 1155/880/1311 1209/744/1111 1230/742/1109 +f 1155/880/1311 1230/742/1109 1218/899/1312 +f 1156/883/1313 1167/751/1119 1157/887/1314 +f 1156/884/1313 1201/886/1315 1165/874/1305 +f 1157/887/1314 1168/752/1120 1158/890/1316 +f 1157/885/1314 1201/886/1315 1156/884/1313 +f 1157/885/1314 1202/889/1317 1201/886/1315 +f 1158/888/1316 1202/889/1317 1157/885/1314 +f 1159/881/1318 1214/898/1310 1234/896/1308 +f 1159/881/1318 1234/896/1308 1220/900/1319 +f 1159/741/1318 1218/899/1312 1230/742/1109 +f 1159/741/1318 1230/742/1109 1210/743/1110 +f 1160/855/1288 1199/851/1297 1137/854/1287 +f 1161/859/1291 1197/848/1296 1140/858/1290 +f 1162/857/1289 1199/851/1297 1139/853/1286 +f 1163/877/1303 1190/893/1216 1222/901/1320 +f 1163/725/1303 1204/727/1093 1150/724/1090 +f 1163/725/1303 1207/734/1101 1228/726/1092 +f 1163/725/1303 1228/726/1092 1204/727/1093 +f 1163/725/1303 1215/895/1307 1225/738/1105 +f 1163/725/1303 1225/738/1105 1207/734/1101 +f 1164/872/1302 1195/870/1202 1150/871/1090 +f 1165/873/1305 1166/749/1116 1156/883/1313 +f 1165/874/1305 1200/875/1304 1151/866/1300 +f 1165/874/1305 1201/886/1315 1200/875/1304 +f 1166/749/1116 1167/751/1119 1156/883/1313 +f 1167/751/1119 1168/752/1120 1157/887/1314 +f 1168/754/1120 1202/889/1317 1158/888/1316 +f 1170/794/1233 1172/791/1235 1096/790/1254 +f 1174/894/1221 1176/761/1222 1175/760/1268 +f 1175/760/1268 1176/761/1222 1077/703/1059 +f 1176/761/1222 1177/697/1223 1077/703/1059 +f 1178/778/1245 1179/700/1227 1108/690/1220 +f 1180/844/1193 1181/845/1194 1008/816/1161 +f 1181/845/1194 1183/820/1173 1008/816/1161 +f 1181/845/1194 1184/851/1197 1183/820/1173 +f 1182/848/1195 1184/851/1197 1181/845/1194 +f 1183/820/1173 1184/851/1197 1023/846/1187 +f 1185/878/1205 1190/893/1216 1052/877/1089 +f 1185/878/1205 1222/901/1320 1190/893/1216 +f 1186/891/1214 1220/900/1319 1234/896/1308 +f 1186/891/1214 1234/896/1308 1217/897/1309 +f 1186/891/1214 1223/879/1206 1043/876/1123 +f 1187/755/1121 1194/889/1213 1188/902/1321 +f 1187/755/1121 1202/889/1317 1168/754/1120 +f 1188/902/1321 1193/886/1210 1189/903/1322 +f 1188/902/1321 1194/889/1213 1193/886/1210 +f 1188/902/1321 1202/889/1317 1187/755/1121 +f 1189/903/1322 1193/886/1210 1192/875/1204 +f 1189/903/1322 1201/886/1315 1188/902/1321 +f 1190/893/1216 1195/870/1202 1039/871/1088 +f 1191/882/1207 1224/892/1215 1048/881/1108 +f 1192/875/1204 1193/886/1210 1054/874/1203 +f 1192/875/1204 1195/867/1202 1189/903/1322 +f 1193/886/1210 1194/889/1213 1046/885/1209 +f 1195/867/1202 1200/875/1304 1189/903/1322 +f 1196/845/1275 1197/848/1296 1133/847/1294 +f 1196/845/1275 1199/851/1297 1197/848/1296 +f 1197/848/1296 1199/851/1297 1160/855/1288 +f 1198/820/1276 1199/851/1297 1196/845/1275 +f 1200/875/1304 1201/886/1315 1189/903/1322 +f 1201/886/1315 1202/889/1317 1188/902/1321 +f 1203/728/1094 1052/725/1089 956/722/1086 +f 1205/737/1104 1043/757/1123 960/733/1100 +f 1208/740/1107 1227/904/1323 1210/743/1110 +f 1208/740/1107 1210/743/1110 961/739/1106 +f 1209/905/1111 1235/906/1324 1211/747/1113 +f 1209/905/1111 1211/747/1113 961/745/1106 +f 1210/743/1110 1227/904/1323 1213/907/1325 +f 1210/743/1110 1213/907/1325 1159/741/1318 +f 1211/747/1113 1235/906/1324 1219/908/1326 +f 1211/747/1113 1219/908/1326 1191/882/1207 +f 1212/758/1124 1229/909/1327 1213/907/1325 +f 1212/758/1124 1213/907/1325 965/756/1122 +f 1213/907/1325 1227/904/1323 1208/740/1107 +f 1213/907/1325 1208/740/1107 965/756/1122 +f 1213/907/1325 1229/909/1327 1214/910/1310 +f 1213/907/1325 1214/910/1310 1159/741/1318 +f 1214/910/1310 1229/909/1327 1212/758/1124 +f 1214/910/1310 1212/758/1124 1154/757/1306 +f 1215/911/1307 1232/913/1329 1216/912/1328 +f 1215/911/1307 1216/912/1328 1154/876/1306 +f 1216/912/1328 1231/914/1330 1217/897/1309 +f 1216/912/1328 1217/897/1309 1154/876/1306 +f 1216/912/1328 1232/913/1329 1222/901/1320 +f 1216/912/1328 1222/901/1320 1185/878/1205 +f 1217/897/1309 1231/914/1330 1223/879/1206 +f 1217/897/1309 1223/879/1206 1186/891/1214 +f 1218/915/1312 1236/916/1331 1219/908/1326 +f 1218/915/1312 1219/908/1326 1155/746/1311 +f 1219/908/1326 1235/906/1324 1209/905/1111 +f 1219/908/1326 1209/905/1111 1155/746/1311 +f 1219/908/1326 1236/916/1331 1221/917/1332 +f 1219/908/1326 1221/917/1332 1191/882/1207 +f 1220/900/1319 1233/918/1333 1221/917/1332 +f 1220/900/1319 1221/917/1332 1159/881/1318 +f 1221/917/1332 1233/918/1333 1224/892/1215 +f 1221/917/1332 1224/892/1215 1191/882/1207 +f 1221/917/1332 1236/916/1331 1218/915/1312 +f 1221/917/1332 1218/915/1312 1159/881/1318 +f 1222/901/1320 1232/913/1329 1215/911/1307 +f 1222/901/1320 1215/911/1307 1163/877/1303 +f 1223/879/1206 1231/914/1330 1216/912/1328 +f 1223/879/1206 1216/912/1328 1185/878/1205 +f 1224/892/1215 1233/918/1333 1220/900/1319 +f 1224/892/1215 1220/900/1319 1186/891/1214 +usemtl archer_boots +g Ar_Ropie_D01_Boots_archer_boots +s 1 +f 461/298/525 473/300/527 466/299/526 +f 461/298/525 508/302/529 462/301/528 +f 461/298/525 510/303/530 508/302/529 +f 462/301/528 473/300/527 461/298/525 +f 462/301/528 474/304/531 473/300/527 +f 462/301/528 518/306/533 463/305/532 +f 463/305/532 474/304/531 462/301/528 +f 463/305/532 475/307/534 474/304/531 +f 463/305/532 476/308/535 475/307/534 +f 463/305/532 479/310/537 464/309/536 +f 463/305/532 480/311/538 476/308/535 +f 463/305/532 511/312/539 479/310/537 +f 463/305/532 518/306/533 511/312/539 +f 464/309/536 479/310/537 465/313/540 +f 464/309/536 480/311/538 463/305/532 +f 465/313/540 477/314/541 476/308/535 +f 465/313/540 478/315/542 477/314/541 +f 465/313/540 480/311/538 464/309/536 +f 465/313/540 519/317/543 466/316/526 +f 466/316/526 478/315/542 465/313/540 +f 466/299/526 507/318/544 461/298/525 +f 466/316/526 519/317/543 507/319/544 +f 467/320/545 527/322/547 468/321/546 +f 467/320/545 532/323/548 527/322/547 +f 467/324/545 538/326/550 472/325/549 +f 468/321/546 527/322/547 469/327/551 +f 468/328/546 538/330/550 467/329/545 +f 469/331/551 493/332/552 468/328/546 +f 469/331/551 501/334/554 491/333/553 +f 469/331/551 502/335/555 501/334/554 +f 469/327/551 528/337/557 470/336/556 +f 470/338/556 502/335/555 469/331/551 +f 470/336/556 530/340/559 471/339/558 +f 471/341/558 495/343/561 492/342/560 +f 471/341/558 502/335/555 470/338/556 +f 471/341/558 503/344/562 502/335/555 +f 471/339/558 530/340/559 472/345/549 +f 472/325/549 495/343/561 471/341/558 +f 472/346/549 531/347/563 467/320/545 +f 472/325/549 538/326/550 495/343/561 +f 473/300/527 478/348/542 466/299/526 +f 473/300/527 526/349/564 478/348/542 +f 474/304/531 526/349/564 473/300/527 +f 474/304/531 527/322/547 526/349/564 +f 475/307/534 527/322/547 474/304/531 +f 475/307/534 528/337/557 527/322/547 +f 475/307/534 529/350/565 528/337/557 +f 476/308/535 480/311/538 465/313/540 +f 476/308/535 529/350/565 475/307/534 +f 476/308/535 530/340/559 529/350/565 +f 477/314/541 530/340/559 476/308/535 +f 477/314/541 531/351/563 530/340/559 +f 478/315/542 531/351/563 477/314/541 +f 479/310/537 506/352/566 465/313/540 +f 479/310/537 509/353/567 506/352/566 +f 479/310/537 511/312/539 509/353/567 +f 481/354/568 535/356/570 482/355/569 +f 481/354/568 536/357/571 535/356/570 +f 481/358/568 537/360/572 536/359/571 +f 482/361/569 485/363/573 481/362/568 +f 482/355/569 533/365/575 483/364/574 +f 482/355/569 535/356/570 533/365/575 +f 483/366/574 484/367/576 482/361/569 +f 483/366/574 533/368/575 484/367/576 +f 484/367/576 485/363/573 482/361/569 +f 484/369/576 534/371/577 485/370/573 +f 485/370/573 537/360/572 481/358/568 +f 486/372/578 496/374/580 490/373/579 +f 486/372/578 497/375/581 496/374/580 +f 486/372/578 501/334/554 487/376/582 +f 486/372/578 504/377/583 501/334/554 +f 487/376/582 497/375/581 486/372/578 +f 487/376/582 503/344/562 488/378/584 +f 488/378/584 497/375/581 487/376/582 +f 488/378/584 498/379/585 497/375/581 +f 488/378/584 505/381/587 489/380/586 +f 489/380/586 498/379/585 488/378/584 +f 489/380/586 499/382/588 498/379/585 +f 489/383/586 500/385/589 499/384/588 +f 489/383/586 505/387/587 490/386/579 +f 490/386/579 500/385/589 489/383/586 +f 490/373/579 504/377/583 486/372/578 +f 490/386/579 505/387/587 504/388/583 +f 491/333/553 493/332/552 469/331/551 +f 491/389/553 505/387/587 492/390/560 +f 491/389/553 534/391/577 533/368/575 +f 491/333/553 535/356/570 493/332/552 +f 492/342/560 503/344/562 471/341/558 +f 492/342/560 505/381/587 503/344/562 +f 492/390/560 534/391/577 491/389/553 +f 492/342/560 537/360/572 534/371/577 +f 493/332/552 535/356/570 494/392/590 +f 493/332/552 538/330/550 468/328/546 +f 494/393/590 537/360/572 495/343/561 +f 494/392/590 538/330/550 493/332/552 +f 495/343/561 537/360/572 492/342/560 +f 495/343/561 538/326/550 494/393/590 +f 496/374/580 500/394/589 490/373/579 +f 497/375/581 498/395/585 496/374/580 +f 498/395/585 500/394/589 496/374/580 +f 499/396/588 500/394/589 498/395/585 +f 501/334/554 502/335/555 487/376/582 +f 501/334/554 504/377/583 491/333/553 +f 502/335/555 503/344/562 487/376/582 +f 503/344/562 505/381/587 488/378/584 +f 504/388/583 505/387/587 491/389/553 +f 506/352/566 519/317/543 465/313/540 +f 506/352/566 520/397/591 519/317/543 +f 507/318/544 510/303/530 461/298/525 +f 507/318/544 525/398/592 510/303/530 +f 508/302/529 518/306/533 462/301/528 +f 508/302/529 524/399/593 518/306/533 +f 509/353/567 520/397/591 506/352/566 +f 509/353/567 522/400/594 520/397/591 +f 509/353/567 523/401/595 522/400/594 +f 510/303/530 524/399/593 508/302/529 +f 510/303/530 525/398/592 521/402/596 +f 511/312/539 523/401/595 509/353/567 +f 512/403/597 522/400/594 515/404/598 +f 513/405/599 525/407/592 516/406/600 +f 514/408/601 521/402/596 516/409/600 +f 514/408/601 524/399/593 521/402/596 +f 515/410/598 520/412/591 512/411/597 +f 515/404/598 522/400/594 517/413/602 +f 515/410/598 539/414/603 520/412/591 +f 516/409/600 521/402/596 513/415/599 +f 516/406/600 524/417/593 514/416/601 +f 516/406/600 539/414/603 524/417/593 +f 517/418/602 523/419/595 515/410/598 +f 518/306/533 523/401/595 511/312/539 +f 518/420/533 539/414/603 523/419/595 +f 519/317/543 525/421/592 507/319/544 +f 519/422/543 539/414/603 525/407/592 +f 520/397/591 522/400/594 512/403/597 +f 520/412/591 539/414/603 519/422/543 +f 521/402/596 524/399/593 510/303/530 +f 521/402/596 525/398/592 513/415/599 +f 522/400/594 523/401/595 517/413/602 +f 523/419/595 539/414/603 515/410/598 +f 524/417/593 539/414/603 518/420/533 +f 525/407/592 539/414/603 516/406/600 +f 526/349/564 531/347/563 478/348/542 +f 526/349/564 532/323/548 531/347/563 +f 527/322/547 528/337/557 469/327/551 +f 527/322/547 532/323/548 526/349/564 +f 528/337/557 529/350/565 470/336/556 +f 529/350/565 530/340/559 470/336/556 +f 530/340/559 531/351/563 472/345/549 +f 531/347/563 532/323/548 467/320/545 +f 533/368/575 534/391/577 484/367/576 +f 533/365/575 535/356/570 491/333/553 +f 534/371/577 537/360/572 485/370/573 +f 535/356/570 536/357/571 494/392/590 +f 536/359/571 537/360/572 494/393/590 +f 540/298/604 552/300/606 541/301/605 +f 540/298/604 586/318/608 545/299/607 +f 540/298/604 589/303/609 586/318/608 +f 541/301/605 553/304/611 542/305/610 +f 541/301/605 587/302/612 540/298/604 +f 541/301/605 597/306/613 587/302/612 +f 542/305/610 559/311/615 543/309/614 +f 542/305/610 597/306/613 541/301/605 +f 543/309/614 558/310/616 542/305/610 +f 543/309/614 559/311/615 544/313/617 +f 544/313/617 557/315/618 545/316/607 +f 544/313/617 558/310/616 543/309/614 +f 544/313/617 559/311/615 555/308/619 +f 544/313/617 585/352/620 558/310/616 +f 544/313/617 598/317/621 585/352/620 +f 545/299/607 552/300/606 540/298/604 +f 545/299/607 557/348/618 552/300/606 +f 545/316/607 598/317/621 544/313/617 +f 546/320/622 610/347/624 551/346/623 +f 546/320/622 611/323/625 610/347/624 +f 546/329/622 617/330/627 547/328/626 +f 547/328/626 572/332/629 548/331/628 +f 547/321/626 606/322/630 546/320/622 +f 547/328/626 617/330/627 572/332/629 +f 548/331/628 572/332/629 570/333/631 +f 548/331/628 581/335/633 549/338/632 +f 548/327/628 606/322/630 547/321/626 +f 548/327/628 607/337/634 606/322/630 +f 549/338/632 581/335/633 550/341/635 +f 549/336/632 607/337/634 548/327/628 +f 549/336/632 608/350/636 607/337/634 +f 549/336/632 609/340/637 608/350/636 +f 550/341/635 574/343/638 551/325/623 +f 550/341/635 582/344/640 571/342/639 +f 550/339/635 609/340/637 549/336/632 +f 551/345/623 609/340/637 550/339/635 +f 551/345/623 610/351/624 609/340/637 +f 551/325/623 617/326/627 546/324/622 +f 552/300/606 553/304/611 541/301/605 +f 552/300/606 605/349/641 553/304/611 +f 553/304/611 554/307/642 542/305/610 +f 553/304/611 606/322/630 554/307/642 +f 554/307/642 555/308/619 542/305/610 +f 554/307/642 608/350/636 555/308/619 +f 555/308/619 556/314/643 544/313/617 +f 555/308/619 559/311/615 542/305/610 +f 555/308/619 609/340/637 556/314/643 +f 556/314/643 557/315/618 544/313/617 +f 556/314/643 610/351/624 557/315/618 +f 557/348/618 605/349/641 552/300/606 +f 557/348/618 610/347/624 605/349/641 +f 558/310/616 590/312/644 542/305/610 +f 560/362/645 564/363/647 561/361/646 +f 560/358/645 616/360/648 564/370/647 +f 561/361/646 563/367/650 562/366/649 +f 561/361/646 564/363/647 563/367/650 +f 561/355/646 614/356/651 560/354/645 +f 562/364/649 612/365/652 561/355/646 +f 563/367/650 612/368/652 562/366/649 +f 563/367/650 613/391/653 612/368/652 +f 564/370/647 613/371/653 563/369/650 +f 564/370/647 616/360/648 613/371/653 +f 565/372/654 576/375/656 566/376/655 +f 565/372/654 583/377/658 569/373/657 +f 566/376/655 576/375/656 567/378/659 +f 566/376/655 580/334/660 565/372/654 +f 566/376/655 581/335/633 580/334/660 +f 566/376/655 582/344/640 581/335/633 +f 567/378/659 577/379/662 568/380/661 +f 567/378/659 582/344/640 566/376/655 +f 567/378/659 584/381/663 582/344/640 +f 568/383/661 579/385/664 569/386/657 +f 568/380/661 584/381/663 567/378/659 +f 569/373/657 575/374/665 565/372/654 +f 569/373/657 579/394/664 575/374/665 +f 569/386/657 584/387/663 568/383/661 +f 570/333/631 580/334/660 548/331/628 +f 570/333/631 583/377/658 580/334/660 +f 570/389/631 584/387/663 583/388/658 +f 570/389/631 613/391/653 571/390/639 +f 570/333/631 614/356/651 612/365/652 +f 571/342/639 574/343/638 550/341/635 +f 571/390/639 584/387/663 570/389/631 +f 571/342/639 616/360/648 574/343/638 +f 572/332/629 614/356/651 570/333/631 +f 572/332/629 617/330/627 573/392/666 +f 573/392/666 614/356/651 572/332/629 +f 573/392/666 615/357/667 614/356/651 +f 573/393/666 616/360/648 615/359/667 +f 573/393/666 617/326/627 574/343/638 +f 574/343/638 616/360/648 573/393/666 +f 574/343/638 617/326/627 551/325/623 +f 575/374/665 576/375/656 565/372/654 +f 575/374/665 577/395/662 576/375/656 +f 575/374/665 579/394/664 577/395/662 +f 576/375/656 577/379/662 567/378/659 +f 577/379/662 578/382/668 568/380/661 +f 577/395/662 579/394/664 578/396/668 +f 578/384/668 579/385/664 568/383/661 +f 580/334/660 581/335/633 548/331/628 +f 580/334/660 583/377/658 565/372/654 +f 581/335/633 582/344/640 550/341/635 +f 582/344/640 584/381/663 571/342/639 +f 583/388/658 584/387/663 569/386/657 +f 585/352/620 588/353/669 558/310/616 +f 585/352/620 599/397/670 588/353/669 +f 586/319/608 598/317/621 545/316/607 +f 586/319/608 604/421/671 598/317/621 +f 587/302/612 589/303/609 540/298/604 +f 587/302/612 603/399/672 589/303/609 +f 588/353/669 590/312/644 558/310/616 +f 588/353/669 602/401/673 590/312/644 +f 589/303/609 603/399/672 600/402/674 +f 589/303/609 604/398/671 586/318/608 +f 590/312/644 597/306/613 542/305/610 +f 590/312/644 602/401/673 597/306/613 +f 591/411/675 599/412/670 594/410/676 +f 591/403/675 601/400/677 599/397/670 +f 592/415/678 600/402/674 595/409/679 +f 592/415/678 604/398/671 600/402/674 +f 593/416/680 603/417/672 595/406/679 +f 594/404/676 601/400/677 591/403/675 +f 594/410/676 602/419/673 596/418/681 +f 594/410/676 618/414/682 602/419/673 +f 595/409/679 600/402/674 593/408/680 +f 595/406/679 604/407/671 592/405/678 +f 595/406/679 618/414/682 604/407/671 +f 596/413/681 601/400/677 594/404/676 +f 596/413/681 602/401/673 601/400/677 +f 597/306/613 603/399/672 587/302/612 +f 597/420/613 618/414/682 603/417/672 +f 598/317/621 599/397/670 585/352/620 +f 598/422/621 618/414/682 599/412/670 +f 599/397/670 601/400/677 588/353/669 +f 599/412/670 618/414/682 594/410/676 +f 600/402/674 603/399/672 593/408/680 +f 600/402/674 604/398/671 589/303/609 +f 601/400/677 602/401/673 588/353/669 +f 602/419/673 618/414/682 597/420/613 +f 603/417/672 618/414/682 595/406/679 +f 604/407/671 618/414/682 598/422/621 +f 605/349/641 606/322/630 553/304/611 +f 605/349/641 611/323/625 606/322/630 +f 606/322/630 607/337/634 554/307/642 +f 606/322/630 611/323/625 546/320/622 +f 607/337/634 608/350/636 554/307/642 +f 608/350/636 609/340/637 555/308/619 +f 609/340/637 610/351/624 556/314/643 +f 610/347/624 611/323/625 605/349/641 +f 612/368/652 613/391/653 570/389/631 +f 612/365/652 614/356/651 561/355/646 +f 613/371/653 616/360/648 571/342/639 +f 614/356/651 615/357/667 560/354/645 +f 615/359/667 616/360/648 560/358/645 +usemtl archer_face +g Ar_Head01_archer_face +s 1 +f 808/543/905 827/545/907 812/544/906 +f 808/543/905 884/547/909 809/546/908 +f 808/543/905 885/548/910 884/547/909 +f 809/546/908 826/549/911 808/543/905 +f 809/546/908 835/550/912 826/549/911 +f 809/546/908 893/552/914 810/551/913 +f 810/551/913 835/550/912 809/546/908 +f 810/551/913 867/553/915 835/550/912 +f 810/551/913 893/552/914 867/553/915 +f 811/554/916 870/556/918 813/555/917 +f 811/554/916 886/557/919 812/544/906 +f 811/554/916 902/558/920 886/557/919 +f 811/554/916 925/559/921 902/558/920 +f 812/544/906 828/560/922 811/554/916 +f 812/544/906 885/548/910 808/543/905 +f 812/544/906 886/557/919 885/548/910 +f 813/555/917 925/559/921 811/554/916 +f 814/561/923 866/563/925 841/562/924 +f 814/561/923 899/564/926 866/563/925 +f 815/565/927 865/567/929 864/566/928 +f 815/565/927 905/569/931 816/568/930 +f 815/565/927 922/570/932 905/569/931 +f 816/568/930 847/571/933 815/565/927 +f 816/568/930 851/572/934 847/571/933 +f 816/568/930 909/574/936 820/573/935 +f 817/575/937 858/577/939 818/576/938 +f 817/578/937 916/580/941 915/579/940 +f 818/576/938 859/582/943 819/581/942 +f 818/583/938 916/580/941 817/578/937 +f 818/583/938 917/584/944 916/580/941 +f 819/585/942 917/584/944 818/583/938 +f 820/573/935 851/572/934 816/568/930 +f 820/573/935 861/586/945 851/572/934 +f 820/573/935 919/588/947 821/587/946 +f 821/587/946 861/586/945 820/573/935 +f 821/587/946 862/589/948 861/586/945 +f 822/590/949 864/566/928 841/562/924 +f 822/590/949 899/564/926 864/566/928 +f 823/591/950 827/545/907 826/549/911 +f 823/591/950 837/593/952 824/592/951 +f 824/592/951 827/545/907 823/591/950 +f 824/592/951 837/593/952 825/594/953 +f 825/594/953 827/545/907 824/592/951 +f 825/594/953 828/560/922 827/545/907 +f 825/594/953 830/595/954 828/560/922 +f 825/594/953 839/597/956 829/596/955 +f 826/549/911 827/545/907 808/543/905 +f 826/549/911 835/550/912 823/591/950 +f 827/545/907 828/560/922 812/544/906 +f 828/560/922 844/598/957 811/554/916 +f 829/596/955 830/595/954 825/594/953 +f 829/596/955 832/599/958 830/595/954 +f 829/596/955 839/597/956 831/600/959 +f 830/595/954 844/598/957 828/560/922 +f 830/595/954 846/601/960 844/598/957 +f 831/600/959 832/599/958 829/596/955 +f 831/600/959 833/602/961 832/599/958 +f 831/600/959 839/597/956 833/602/961 +f 832/599/958 845/603/962 830/595/954 +f 832/599/958 849/604/963 845/603/962 +f 833/602/961 834/605/964 832/599/958 +f 833/602/961 839/597/956 838/606/965 +f 833/602/961 840/607/966 834/605/964 +f 834/605/964 849/604/963 832/599/958 +f 835/550/912 836/608/967 823/591/950 +f 835/550/912 868/609/968 836/608/967 +f 836/608/967 837/593/952 823/591/950 +f 836/608/967 838/606/965 837/593/952 +f 836/608/967 869/610/969 838/606/965 +f 837/593/952 839/597/956 825/594/953 +f 838/606/965 839/597/956 837/593/952 +f 838/606/965 840/607/966 833/602/961 +f 838/606/965 842/611/970 840/607/966 +f 838/606/965 869/610/969 842/611/970 +f 840/607/966 849/604/963 834/605/964 +f 840/607/966 852/612/971 849/604/963 +f 841/562/924 865/567/929 842/611/970 +f 841/562/924 866/563/925 822/590/949 +f 841/562/924 867/553/915 814/561/923 +f 841/562/924 868/609/968 867/553/915 +f 841/562/924 869/610/969 868/609/968 +f 842/611/970 843/613/972 840/607/966 +f 842/611/970 848/614/973 843/613/972 +f 842/611/970 865/567/929 847/571/933 +f 842/611/970 869/610/969 841/562/924 +f 843/613/972 852/612/971 840/607/966 +f 844/598/957 870/556/918 811/554/916 +f 845/603/962 846/601/960 830/595/954 +f 846/601/960 870/556/918 844/598/957 +f 847/571/933 848/614/973 842/611/970 +f 847/571/933 851/572/934 848/614/973 +f 847/571/933 865/567/929 815/565/927 +f 848/614/973 850/615/974 843/613/972 +f 848/614/973 851/572/934 850/615/974 +f 849/604/963 855/616/975 845/603/962 +f 849/617/963 872/619/976 855/618/975 +f 850/615/974 852/612/971 843/613/972 +f 850/615/974 853/620/977 852/612/971 +f 851/572/934 853/620/977 850/615/974 +f 851/572/934 861/586/945 853/620/977 +f 852/621/971 871/622/978 849/617/963 +f 853/620/977 854/623/979 852/612/971 +f 853/620/977 861/586/945 854/623/979 +f 854/623/979 858/577/939 856/624/980 +f 854/623/979 860/625/981 858/577/939 +f 854/623/979 862/589/948 860/625/981 +f 854/626/979 871/622/978 852/621/971 +f 855/616/975 863/627/982 845/603/962 +f 855/628/975 880/630/983 856/629/980 +f 856/624/980 858/577/939 857/631/984 +f 856/624/980 863/627/982 855/616/975 +f 856/629/980 871/622/978 854/626/979 +f 856/629/980 873/632/985 871/622/978 +f 856/629/980 880/630/983 873/632/985 +f 857/631/984 858/577/939 817/575/937 +f 857/631/984 863/627/982 856/624/980 +f 858/577/939 859/582/943 818/576/938 +f 858/577/939 860/625/981 859/582/943 +f 861/586/945 862/589/948 854/623/979 +f 864/566/928 865/567/929 841/562/924 +f 864/566/928 922/570/932 815/565/927 +f 866/563/925 899/564/926 822/590/949 +f 867/553/915 868/609/968 835/550/912 +f 867/553/915 899/564/926 814/561/923 +f 867/553/915 923/633/986 899/564/926 +f 868/609/968 869/610/969 836/608/967 +f 871/622/978 872/619/976 849/617/963 +f 871/622/978 873/632/985 872/619/976 +f 872/619/976 876/635/988 875/634/987 +f 872/619/976 879/636/989 855/618/975 +f 873/632/985 876/635/988 872/619/976 +f 873/632/985 880/630/983 876/635/988 +f 874/637/990 878/638/991 875/634/987 +f 875/634/987 876/635/988 874/637/990 +f 875/634/987 879/636/989 872/619/976 +f 876/635/988 877/639/992 874/637/990 +f 876/635/988 880/630/983 877/639/992 +f 877/639/992 878/640/991 874/637/990 +f 877/639/992 879/641/989 878/640/991 +f 877/639/992 880/630/983 879/641/989 +f 878/638/991 879/636/989 875/634/987 +f 879/641/989 880/630/983 855/628/975 +f 881/642/993 885/548/910 882/643/994 +f 881/642/993 893/552/914 884/547/909 +f 881/642/993 894/644/995 893/552/914 +f 881/642/993 895/645/996 894/644/995 +f 882/643/994 885/548/910 883/646/997 +f 882/643/994 895/645/996 881/642/993 +f 883/646/997 888/648/999 887/647/998 +f 883/646/997 895/645/996 882/643/994 +f 883/646/997 897/649/1000 895/645/996 +f 884/547/909 885/548/910 881/642/993 +f 884/547/909 893/552/914 809/546/908 +f 885/548/910 886/557/919 883/646/997 +f 886/557/919 888/648/999 883/646/997 +f 886/557/919 902/558/920 888/648/999 +f 887/647/998 890/651/1002 889/650/1001 +f 887/647/998 897/649/1000 883/646/997 +f 888/648/999 890/651/1002 887/647/998 +f 888/648/999 903/652/1003 890/651/1002 +f 888/648/999 904/653/1004 903/652/1003 +f 889/650/1001 897/649/1000 887/647/998 +f 890/651/1002 891/654/1005 889/650/1001 +f 890/651/1002 892/655/1006 891/654/1005 +f 890/651/1002 907/656/1007 892/655/1006 +f 891/654/1005 897/649/1000 889/650/1001 +f 891/654/1005 898/658/1009 896/657/1008 +f 892/655/1006 898/658/1009 891/654/1005 +f 892/655/1006 907/656/1007 898/658/1009 +f 893/552/914 923/633/986 867/553/915 +f 894/644/995 923/633/986 893/552/914 +f 894/644/995 924/659/1010 923/633/986 +f 895/645/996 896/657/1008 894/644/995 +f 895/645/996 897/649/1000 896/657/1008 +f 896/657/1008 897/649/1000 891/654/1005 +f 896/657/1008 924/659/1010 894/644/995 +f 898/658/1009 900/660/1011 896/657/1008 +f 898/658/1009 901/661/1012 900/660/1011 +f 898/658/1009 910/662/1013 901/661/1012 +f 899/564/926 922/570/932 864/566/928 +f 899/564/926 924/659/1010 900/660/1011 +f 900/660/1011 906/663/1014 905/569/931 +f 900/660/1011 922/570/932 899/564/926 +f 900/660/1011 924/659/1010 896/657/1008 +f 901/661/1012 906/663/1014 900/660/1011 +f 901/661/1012 908/664/1015 906/663/1014 +f 901/661/1012 910/662/1013 908/664/1015 +f 902/558/920 904/653/1004 888/648/999 +f 902/558/920 925/559/921 904/653/1004 +f 903/652/1003 907/656/1007 890/651/1002 +f 903/652/1003 913/665/1016 907/656/1007 +f 903/652/1003 921/666/1017 913/665/1016 +f 905/569/931 909/574/936 816/568/930 +f 905/569/931 922/570/932 900/660/1011 +f 906/663/1014 909/574/936 905/569/931 +f 907/656/1007 910/662/1013 898/658/1009 +f 907/617/1007 926/622/1018 910/621/1013 +f 907/617/1007 927/619/1019 926/622/1018 +f 908/664/1015 909/574/936 906/663/1014 +f 908/664/1015 911/667/1020 909/574/936 +f 909/574/936 919/588/947 820/573/935 +f 910/662/1013 911/667/1020 908/664/1015 +f 910/662/1013 912/668/1021 911/667/1020 +f 910/621/1013 926/622/1018 912/626/1021 +f 911/667/1020 919/588/947 909/574/936 +f 912/668/1021 919/588/947 911/667/1020 +f 912/668/1021 920/669/1022 919/588/947 +f 912/626/1021 926/622/1018 914/629/1023 +f 913/665/1016 921/666/1017 914/670/1023 +f 913/618/1016 927/619/1019 907/617/1007 +f 913/618/1016 934/636/1024 927/619/1019 +f 913/628/1016 935/630/1025 934/641/1024 +f 914/670/1023 916/580/941 912/668/1021 +f 914/670/1023 921/666/1017 915/579/940 +f 914/629/1023 935/630/1025 913/628/1016 +f 915/579/940 916/580/941 914/670/1023 +f 916/580/941 918/671/1026 912/668/1021 +f 917/584/944 918/671/1026 916/580/941 +f 918/671/1026 920/669/1022 912/668/1021 +f 919/588/947 920/669/1022 821/587/946 +f 923/633/986 924/659/1010 899/564/926 +f 926/622/1018 928/632/1027 914/629/1023 +f 927/619/1019 928/632/1027 926/622/1018 +f 927/619/1019 931/635/1028 928/632/1027 +f 927/619/1019 934/636/1024 930/634/1029 +f 928/632/1027 935/630/1025 914/629/1023 +f 929/637/1030 931/635/1028 930/634/1029 +f 929/637/1030 932/639/1031 931/635/1028 +f 929/637/1030 933/640/1032 932/639/1031 +f 930/634/1029 931/635/1028 927/619/1019 +f 930/634/1029 933/638/1032 929/637/1030 +f 930/634/1029 934/636/1024 933/638/1032 +f 931/635/1028 935/630/1025 928/632/1027 +f 932/639/1031 935/630/1025 931/635/1028 +f 933/640/1032 934/641/1024 932/639/1031 +f 934/641/1024 935/630/1025 932/639/1031 +usemtl archer_hair +g Ar_Hair01_Yellow_archer_hair +s 1 +f 619/423/683 621/425/685 620/424/684 +f 620/424/686 621/425/688 619/423/687 +f 622/426/689 643/428/691 623/427/690 +f 622/426/689 653/429/692 643/428/691 +f 622/426/689 660/431/694 650/430/693 +f 623/427/690 638/432/695 622/426/689 +f 623/427/690 643/428/691 641/433/696 +f 623/427/690 654/435/698 632/434/697 +f 623/427/690 655/436/699 654/435/698 +f 624/437/700 680/439/702 635/438/701 +f 625/440/703 645/442/704 635/441/701 +f 625/440/703 646/443/705 645/442/704 +f 625/444/703 680/439/702 634/445/706 +f 626/446/707 693/448/709 629/447/708 +f 626/446/707 758/448/711 644/449/710 +f 627/450/712 632/434/697 628/451/713 +f 627/450/712 633/452/714 632/434/697 +f 627/450/712 647/453/715 633/452/714 +f 628/451/713 636/454/716 627/450/712 +f 628/451/713 637/455/717 636/454/716 +f 628/451/713 655/436/699 637/455/717 +f 629/447/708 693/448/709 636/454/716 +f 629/447/708 706/455/719 705/454/718 +f 629/447/708 758/448/711 626/446/707 +f 630/456/720 651/458/722 631/457/721 +f 630/456/720 692/459/723 651/458/722 +f 631/457/721 639/460/724 630/456/720 +f 631/457/721 660/431/694 638/432/695 +f 632/434/697 638/432/695 623/427/690 +f 632/434/697 639/460/724 638/432/695 +f 632/434/697 654/435/698 628/451/713 +f 633/452/714 639/460/724 632/434/697 +f 633/452/714 640/461/725 639/460/724 +f 633/452/714 648/462/726 640/461/725 +f 634/463/706 646/443/705 625/440/703 +f 634/463/706 647/453/715 646/443/705 +f 634/463/706 673/464/727 647/453/715 +f 634/465/706 680/466/702 673/464/727 +f 635/441/701 644/468/710 624/467/700 +f 635/441/701 645/442/704 644/449/710 +f 635/438/701 680/439/702 625/444/703 +f 636/454/716 637/455/717 629/447/708 +f 636/454/716 646/443/705 627/450/712 +f 636/454/716 693/448/709 645/442/704 +f 637/455/717 656/469/728 629/447/708 +f 638/432/695 639/460/724 631/457/721 +f 638/432/695 660/431/694 622/426/689 +f 639/460/724 640/461/725 630/456/720 +f 640/461/725 666/470/729 630/456/720 +f 641/433/696 655/436/699 623/427/690 +f 641/433/696 685/471/730 655/436/699 +f 642/472/731 675/474/733 667/473/732 +f 643/428/691 684/475/734 641/433/696 +f 643/428/691 686/476/735 684/475/734 +f 644/449/710 693/448/709 626/446/707 +f 644/468/710 704/441/736 624/467/700 +f 644/449/710 713/442/737 704/441/736 +f 644/449/710 758/448/711 713/442/737 +f 645/442/704 646/443/705 636/454/716 +f 645/442/704 693/448/709 644/449/710 +f 646/443/705 647/453/715 627/450/712 +f 647/453/715 648/462/726 633/452/714 +f 647/453/715 673/464/727 648/462/726 +f 648/462/726 666/470/729 640/461/725 +f 648/462/726 678/478/739 649/477/738 +f 649/477/738 666/470/729 648/462/726 +f 649/477/738 671/479/740 666/470/729 +f 649/477/738 678/478/739 671/479/740 +f 650/430/693 653/429/692 622/426/689 +f 650/430/693 657/480/741 653/429/692 +f 650/430/693 660/431/694 652/481/742 +f 650/430/693 683/482/743 657/480/741 +f 651/458/722 652/481/742 631/457/721 +f 651/458/722 658/483/744 652/481/742 +f 651/458/722 692/459/723 658/483/744 +f 652/481/742 659/484/745 650/430/693 +f 652/481/742 660/431/694 631/457/721 +f 653/429/692 686/476/735 643/428/691 +f 653/429/692 692/485/723 686/476/735 +f 654/435/698 655/436/699 628/451/713 +f 655/436/699 656/469/728 637/455/717 +f 655/436/699 685/471/730 656/469/728 +f 656/469/728 706/455/719 629/447/708 +f 656/469/728 723/436/746 706/455/719 +f 657/480/741 683/482/743 663/486/747 +f 657/480/741 691/487/748 653/429/692 +f 658/483/744 659/484/745 652/481/742 +f 658/483/744 665/488/749 659/484/745 +f 658/483/744 679/490/751 664/489/750 +f 658/483/744 692/459/723 679/490/751 +f 659/484/745 683/482/743 650/430/693 +f 661/491/752 681/493/754 662/492/753 +f 661/491/752 689/494/755 681/493/754 +f 662/495/753 663/486/747 661/496/752 +f 662/495/753 679/497/751 663/486/747 +f 662/492/753 681/493/754 664/489/750 +f 663/486/747 679/497/751 657/480/741 +f 663/486/747 682/498/756 661/496/752 +f 663/486/747 683/482/743 665/488/749 +f 664/489/750 665/488/749 658/483/744 +f 664/489/750 674/499/757 665/488/749 +f 664/489/750 679/490/751 662/492/753 +f 664/489/750 681/493/754 674/499/757 +f 665/488/749 674/499/757 663/486/747 +f 665/488/749 683/482/743 659/484/745 +f 666/470/729 692/459/723 630/456/720 +f 667/500/732 670/501/758 642/472/731 +f 667/473/732 675/474/733 668/502/759 +f 668/503/759 669/504/760 667/500/732 +f 668/503/759 672/505/761 669/504/760 +f 668/502/759 676/507/762 672/506/761 +f 669/504/760 670/501/758 667/500/732 +f 669/504/760 672/505/761 671/479/740 +f 669/504/760 676/507/762 670/501/758 +f 669/504/760 677/508/763 676/507/762 +f 670/501/758 675/474/733 642/472/731 +f 670/501/758 676/507/762 675/474/733 +f 671/479/740 672/505/761 666/470/729 +f 671/479/740 677/508/763 669/504/760 +f 671/479/740 678/478/739 677/508/763 +f 672/506/761 677/508/763 666/509/729 +f 673/464/727 678/478/739 648/462/726 +f 673/464/727 680/466/702 678/478/739 +f 674/499/757 682/498/756 663/486/747 +f 674/499/757 687/510/764 682/498/756 +f 674/499/757 688/511/765 687/510/764 +f 675/474/733 676/507/762 668/502/759 +f 676/507/762 677/508/763 672/506/761 +f 677/508/763 678/478/739 666/509/729 +f 678/478/739 680/466/702 666/509/729 +f 679/497/751 691/487/748 657/480/741 +f 679/497/751 692/485/723 691/487/748 +f 681/493/754 688/511/765 674/499/757 +f 681/493/754 689/494/755 688/511/765 +f 682/498/756 689/512/755 661/496/752 +f 682/498/756 690/513/766 689/512/755 +f 684/475/734 685/471/730 641/433/696 +f 684/475/734 686/476/735 666/514/729 +f 684/475/734 710/433/767 685/471/730 +f 684/475/734 712/428/768 710/433/767 +f 684/475/734 751/476/769 712/428/768 +f 685/471/730 723/436/746 656/469/728 +f 686/476/735 692/485/723 666/514/729 +f 687/510/764 690/513/766 682/498/756 +f 688/511/765 690/513/766 687/510/764 +f 689/494/755 690/513/766 688/511/765 +f 691/487/748 692/485/723 653/429/692 +f 694/426/770 707/432/772 695/427/771 +f 694/426/770 721/429/774 718/430/773 +f 694/426/770 727/431/775 707/432/772 +f 695/427/771 707/432/772 701/434/776 +f 695/427/771 712/428/768 694/426/770 +f 695/427/771 723/436/746 710/433/767 +f 696/440/777 714/443/779 703/463/778 +f 696/444/777 747/439/780 704/438/736 +f 697/450/781 705/454/718 698/451/782 +f 697/450/781 714/443/779 705/454/718 +f 697/450/781 715/453/783 714/443/779 +f 698/451/782 701/434/776 697/450/781 +f 698/451/782 722/435/784 701/434/776 +f 698/451/782 723/436/746 722/435/784 +f 699/456/785 708/460/787 700/457/786 +f 699/456/785 709/461/788 708/460/787 +f 699/456/785 733/470/789 709/461/788 +f 699/456/785 757/459/790 733/470/789 +f 700/457/786 708/460/787 707/432/772 +f 700/457/786 719/458/791 699/456/785 +f 700/457/786 720/481/792 719/458/791 +f 700/457/786 727/431/775 720/481/792 +f 701/434/776 702/452/793 697/450/781 +f 701/434/776 708/460/787 702/452/793 +f 701/434/776 722/435/784 695/427/771 +f 702/452/793 715/453/783 697/450/781 +f 702/452/793 716/462/794 715/453/783 +f 703/445/778 747/439/780 696/444/777 +f 704/441/736 713/442/737 696/440/777 +f 704/438/736 747/439/780 624/437/700 +f 705/454/718 706/455/719 698/451/782 +f 705/454/718 714/443/779 713/442/737 +f 705/454/718 758/448/711 629/447/708 +f 706/455/719 723/436/746 698/451/782 +f 707/432/772 708/460/787 701/434/776 +f 707/432/772 727/431/775 700/457/786 +f 708/460/787 709/461/788 702/452/793 +f 709/461/788 716/462/794 702/452/793 +f 709/461/788 733/470/789 716/462/794 +f 710/433/767 712/428/768 695/427/771 +f 710/433/767 723/436/746 685/471/730 +f 711/472/795 737/501/797 734/500/796 +f 711/472/795 742/474/798 737/501/797 +f 712/428/768 721/429/774 694/426/770 +f 712/428/768 751/476/769 721/429/774 +f 713/442/737 714/443/779 696/440/777 +f 713/442/737 758/448/711 705/454/718 +f 714/443/779 715/453/783 703/463/778 +f 715/453/783 740/464/799 703/463/778 +f 716/462/794 733/470/789 717/477/800 +f 716/462/794 740/464/799 715/453/783 +f 716/462/794 745/478/801 740/464/799 +f 717/477/800 745/478/801 716/462/794 +f 718/430/773 726/484/802 720/481/792 +f 718/430/773 727/431/775 694/426/770 +f 718/430/773 750/482/803 726/484/802 +f 719/458/791 757/459/790 699/456/785 +f 720/481/792 725/483/804 719/458/791 +f 720/481/792 726/484/802 725/483/804 +f 720/481/792 727/431/775 718/430/773 +f 721/429/774 724/480/805 718/430/773 +f 721/429/774 756/487/806 724/480/805 +f 721/429/774 757/485/790 756/487/806 +f 722/435/784 723/436/746 695/427/771 +f 724/480/805 746/497/808 730/486/807 +f 724/480/805 750/482/803 718/430/773 +f 724/480/805 756/487/806 746/497/808 +f 725/483/804 732/488/810 731/489/809 +f 725/483/804 757/459/790 719/458/791 +f 726/484/802 732/488/810 725/483/804 +f 726/484/802 750/482/803 732/488/810 +f 728/496/811 730/486/807 729/495/812 +f 728/496/811 749/498/813 730/486/807 +f 728/496/811 754/512/814 749/498/813 +f 729/492/812 746/490/808 731/489/809 +f 729/492/812 748/493/815 728/491/811 +f 730/486/807 741/499/816 732/488/810 +f 730/486/807 746/497/808 729/495/812 +f 730/486/807 749/498/813 741/499/816 +f 730/486/807 750/482/803 724/480/805 +f 731/489/809 746/490/808 725/483/804 +f 731/489/809 748/493/815 729/492/812 +f 732/488/810 748/493/815 731/489/809 +f 732/488/810 750/482/803 730/486/807 +f 733/470/789 738/479/817 717/477/800 +f 733/470/789 739/505/818 738/479/817 +f 733/509/789 744/508/819 739/506/818 +f 733/509/789 745/478/801 744/508/819 +f 733/509/789 747/466/780 745/478/801 +f 733/514/789 751/476/769 684/475/734 +f 733/514/789 757/485/790 751/476/769 +f 734/500/796 736/504/821 735/503/820 +f 734/500/796 737/501/797 736/504/821 +f 734/473/796 742/474/798 711/472/795 +f 735/502/820 742/474/798 734/473/796 +f 735/502/820 743/507/822 742/474/798 +f 736/504/821 739/505/818 735/503/820 +f 736/504/821 744/508/819 738/479/817 +f 737/501/797 743/507/822 736/504/821 +f 738/479/817 739/505/818 736/504/821 +f 738/479/817 745/478/801 717/477/800 +f 739/506/818 743/507/822 735/502/820 +f 739/506/818 744/508/819 743/507/822 +f 740/464/799 747/466/780 703/465/778 +f 741/499/816 748/493/815 732/488/810 +f 741/499/816 752/510/823 748/493/815 +f 742/474/798 743/507/822 737/501/797 +f 743/507/822 744/508/819 736/504/821 +f 744/508/819 745/478/801 738/479/817 +f 745/478/801 747/466/780 740/464/799 +f 746/490/808 757/459/790 725/483/804 +f 748/493/815 754/494/814 728/491/811 +f 749/498/813 752/510/823 741/499/816 +f 749/498/813 755/513/824 752/510/823 +f 751/476/769 757/485/790 721/429/774 +f 752/510/823 753/511/825 748/493/815 +f 752/510/823 755/513/824 753/511/825 +f 753/511/825 754/494/814 748/493/815 +f 753/511/825 755/513/824 754/494/814 +f 754/512/814 755/513/824 749/498/813 +f 756/487/806 757/485/790 746/497/808 +f 624/467/826 762/515/828 635/441/827 +f 624/467/826 704/441/829 762/515/828 +f 625/440/830 764/516/832 634/463/831 +f 634/463/831 766/517/834 673/464/833 +f 635/441/827 764/516/832 625/440/830 +f 759/518/835 763/519/836 762/515/828 +f 759/518/835 769/519/838 768/520/837 +f 760/521/839 763/519/836 761/520/840 +f 760/521/839 764/516/832 763/519/836 +f 760/521/839 765/522/841 764/516/832 +f 761/520/840 763/519/836 759/518/835 +f 762/515/828 763/519/836 635/441/827 +f 762/515/828 769/519/838 759/518/835 +f 763/519/836 764/516/832 635/441/827 +f 764/516/832 765/522/841 634/463/831 +f 765/522/841 766/517/834 634/463/831 +f 696/440/842 770/516/843 704/441/829 +f 703/463/844 770/516/843 696/440/842 +f 703/463/844 771/522/845 770/516/843 +f 703/463/844 772/517/846 771/522/845 +f 704/441/829 769/519/838 762/515/828 +f 704/441/829 770/516/843 769/519/838 +f 740/464/847 772/517/846 703/463/844 +f 768/520/837 769/519/838 767/521/848 +f 769/519/838 770/516/843 767/521/848 +f 770/516/843 771/522/845 767/521/848 +f 773/523/849 778/525/851 774/524/850 +f 774/526/850 776/528/852 773/527/849 +f 774/524/850 778/525/851 775/529/853 +f 775/530/853 776/528/852 774/526/850 +f 775/530/853 777/531/854 776/528/852 +f 775/529/853 778/525/851 777/532/854 +f 776/528/852 777/531/854 773/527/849 +f 777/532/854 778/525/851 773/523/849 +f 779/527/855 782/528/857 780/526/856 +f 779/527/855 783/531/858 782/528/857 +f 779/523/855 784/525/859 783/532/858 +f 780/526/856 782/528/857 781/530/860 +f 780/524/856 784/525/859 779/523/855 +f 781/529/860 784/525/859 780/524/856 +f 782/528/857 783/531/858 781/530/860 +f 783/532/858 784/525/859 781/529/860 +f 785/533/861 787/535/863 786/534/862 +f 785/533/861 789/536/864 787/535/863 +f 787/535/863 788/537/865 786/534/862 +f 787/535/863 789/536/864 788/537/865 +f 791/534/866 792/535/868 790/533/867 +f 791/534/866 793/537/869 792/535/868 +f 792/535/868 794/536/870 790/533/867 +f 793/537/869 794/536/870 792/535/868 +f 795/538/871 797/423/873 796/539/872 +f 796/539/874 797/423/876 795/538/875 +f 795/538/877 798/425/879 797/423/878 +f 797/423/880 798/425/882 795/538/881 +f 799/540/883 801/542/883 800/541/883 +f 800/541/884 801/542/884 799/540/884 +f 802/540/885 620/424/885 803/541/885 +f 803/541/886 620/424/886 802/540/886 +f 802/540/887 621/425/887 620/424/887 +f 620/424/888 621/425/888 802/540/888 +f 797/423/889 798/425/889 804/424/889 +f 804/424/890 798/425/890 797/423/890 +f 805/538/891 619/423/893 806/539/892 +f 806/539/894 619/423/896 805/538/895 +f 805/538/897 621/425/897 619/423/897 +f 619/423/898 621/425/898 805/538/898 +f 802/540/899 807/542/899 803/541/899 +f 803/541/900 807/542/900 802/540/900 +f 799/540/901 804/424/901 800/541/901 +f 800/541/902 804/424/902 799/540/902 +f 799/540/903 798/425/903 804/424/903 +f 804/424/904 798/425/904 799/540/904 +usemtl archer_legs +g Ar_Ropie_D01_Leg_archer_legs +s 1 +f 1/1/1 3/3/3 2/2/2 +f 2/2/4 3/3/6 1/1/5 +f 4/4/7 17/6/9 14/5/8 +f 4/4/7 107/7/10 17/6/9 +f 5/8/11 69/10/13 68/9/12 +f 5/8/11 72/12/15 10/11/14 +f 5/8/11 271/8/17 24/12/16 +f 5/8/11 24/12/16 20/9/18 +f 5/8/11 272/8/20 21/10/19 +f 5/8/11 21/10/19 8/13/21 +f 6/14/22 84/16/24 7/15/23 +f 6/17/22 107/7/10 65/6/25 +f 7/15/23 70/19/27 9/18/26 +f 7/15/23 83/20/28 70/19/27 +f 7/15/23 84/16/24 83/20/28 +f 7/15/23 268/15/30 36/16/29 +f 7/15/23 36/16/29 6/14/22 +f 8/13/21 21/10/19 267/18/31 +f 8/13/21 267/18/31 9/18/26 +f 8/13/21 69/10/13 5/8/11 +f 9/18/26 22/19/33 269/15/32 +f 9/18/26 269/15/32 7/15/23 +f 9/18/26 69/10/13 8/13/21 +f 9/18/26 70/19/27 69/10/13 +f 10/11/14 24/12/16 271/8/17 +f 10/11/14 271/8/17 5/8/11 +f 11/21/34 21/10/19 20/9/18 +f 11/21/34 23/23/36 12/22/35 +f 11/21/34 25/25/38 15/24/37 +f 12/22/35 25/25/38 11/21/34 +f 13/26/39 17/6/9 16/27/40 +f 13/26/39 25/25/38 12/22/35 +f 14/5/8 17/6/9 13/26/39 +f 15/24/37 19/28/41 11/21/34 +f 15/24/37 25/25/38 16/27/40 +f 15/24/37 33/29/42 19/28/41 +f 16/27/40 25/25/38 13/26/39 +f 16/27/40 32/30/43 15/24/37 +f 17/6/9 32/30/43 16/27/40 +f 17/6/9 37/31/44 32/30/43 +f 17/6/9 107/7/10 6/17/22 +f 17/6/9 6/17/22 270/17/45 +f 18/32/46 30/34/48 27/33/47 +f 18/32/46 42/35/49 30/34/48 +f 18/32/46 47/36/50 42/35/49 +f 18/32/46 48/37/51 47/36/50 +f 19/28/41 21/10/19 11/21/34 +f 19/28/41 22/19/33 21/10/19 +f 19/28/41 34/38/52 22/19/33 +f 20/9/18 21/10/19 272/8/20 +f 20/9/18 272/8/20 5/8/11 +f 20/9/18 23/23/36 11/21/34 +f 20/9/18 24/12/16 23/23/36 +f 21/10/19 22/19/33 9/18/26 +f 21/10/19 9/18/26 267/18/31 +f 22/19/33 35/20/53 7/15/23 +f 22/19/33 7/15/23 269/15/32 +f 26/39/54 38/40/55 27/33/47 +f 27/33/47 38/40/55 18/32/46 +f 28/41/56 43/43/58 31/42/57 +f 29/44/59 38/46/55 26/45/54 +f 29/44/59 46/47/60 38/46/55 +f 30/34/48 43/43/58 28/41/56 +f 31/42/57 44/48/61 29/44/59 +f 32/30/43 33/29/42 15/24/37 +f 32/30/43 41/49/62 33/29/42 +f 32/30/43 45/50/63 41/49/62 +f 33/29/42 34/38/52 19/28/41 +f 33/29/42 40/51/64 34/38/52 +f 33/29/42 41/49/62 40/51/64 +f 34/38/52 35/20/53 22/19/33 +f 34/38/52 39/52/65 35/20/53 +f 34/38/52 40/51/64 39/52/65 +f 35/20/53 36/16/29 268/15/30 +f 35/20/53 268/15/30 7/15/23 +f 35/20/53 54/53/66 36/16/29 +f 35/20/53 55/54/67 54/53/66 +f 36/55/29 37/31/44 17/6/9 +f 36/55/29 45/50/63 37/31/44 +f 36/55/29 53/56/68 45/50/63 +f 36/16/29 54/53/66 53/57/68 +f 37/31/44 45/50/63 32/30/43 +f 38/40/55 48/37/51 18/32/46 +f 38/46/55 49/59/69 48/58/51 +f 39/52/65 55/54/67 35/20/53 +f 39/52/65 56/60/70 55/54/67 +f 40/51/64 56/60/70 39/52/65 +f 40/51/64 57/61/71 56/60/70 +f 41/49/62 57/61/71 40/51/64 +f 41/49/62 58/62/72 57/61/71 +f 42/35/49 43/43/58 30/34/48 +f 42/35/49 52/63/73 43/43/58 +f 43/43/58 44/48/61 31/42/57 +f 43/43/58 51/64/74 44/48/61 +f 43/43/58 52/63/73 51/64/74 +f 44/48/61 46/47/60 29/44/59 +f 44/48/61 50/65/75 46/47/60 +f 44/48/61 51/64/74 50/65/75 +f 45/50/63 58/62/72 41/49/62 +f 46/47/60 49/59/69 38/46/55 +f 46/47/60 50/65/75 49/59/69 +f 47/36/50 52/63/73 42/35/49 +f 47/36/50 359/67/77 350/66/76 +f 47/36/50 350/66/76 52/63/73 +f 47/36/50 360/68/78 359/67/77 +f 48/37/51 357/69/79 360/68/78 +f 48/37/51 360/68/78 47/36/50 +f 48/37/51 358/70/80 357/69/79 +f 49/59/69 354/72/82 356/71/81 +f 49/59/69 356/71/81 48/58/51 +f 49/59/69 355/73/83 354/72/82 +f 50/65/75 352/74/84 355/73/83 +f 50/65/75 355/73/83 49/59/69 +f 50/65/75 353/75/85 352/74/84 +f 51/64/74 351/76/86 353/75/85 +f 51/64/74 353/75/85 50/65/75 +f 52/63/73 349/77/87 351/76/86 +f 52/63/73 351/76/86 51/64/74 +f 52/63/73 350/66/76 349/77/87 +f 53/57/68 54/53/66 357/69/79 +f 53/57/68 357/69/79 358/70/80 +f 53/56/68 58/62/72 45/50/63 +f 54/53/66 55/54/67 359/67/77 +f 54/53/66 359/67/77 360/68/78 +f 55/54/67 56/60/70 349/77/87 +f 55/54/67 349/77/87 350/66/76 +f 55/54/67 350/66/76 359/67/77 +f 56/60/70 57/61/71 352/74/84 +f 56/60/70 352/74/84 353/75/85 +f 57/61/71 58/62/72 354/72/82 +f 57/61/71 354/72/82 355/73/83 +f 59/21/88 67/28/90 63/24/89 +f 59/21/88 69/10/13 67/28/90 +f 59/21/88 71/23/91 68/9/12 +f 59/21/88 73/25/93 60/22/92 +f 60/22/92 71/23/91 59/21/88 +f 60/22/92 73/25/93 61/26/94 +f 61/26/94 65/6/25 62/5/95 +f 61/26/94 73/25/93 64/27/96 +f 62/5/95 65/6/25 4/4/7 +f 63/24/89 73/25/93 59/21/88 +f 63/24/89 80/30/97 64/27/96 +f 63/24/89 81/29/98 80/30/97 +f 64/27/96 65/6/25 61/26/94 +f 64/27/96 73/25/93 63/24/89 +f 64/27/96 80/30/97 65/6/25 +f 65/6/25 84/55/24 6/17/22 +f 65/6/25 85/31/99 84/55/24 +f 65/6/25 107/7/10 4/4/7 +f 66/32/100 86/40/102 75/33/101 +f 66/32/100 96/37/103 86/40/102 +f 67/28/90 81/29/98 63/24/89 +f 67/28/90 82/38/104 81/29/98 +f 68/9/12 69/10/13 59/21/88 +f 68/9/12 72/12/15 5/8/11 +f 69/10/13 70/19/27 67/28/90 +f 70/19/27 82/38/104 67/28/90 +f 70/19/27 83/20/28 82/38/104 +f 71/23/91 72/12/15 68/9/12 +f 74/45/105 86/46/102 77/44/106 +f 75/33/101 78/34/107 66/32/100 +f 75/33/101 86/40/102 74/39/105 +f 76/41/108 91/43/109 78/34/107 +f 77/44/106 92/48/111 79/42/110 +f 77/44/106 94/47/112 92/48/111 +f 78/34/107 90/35/113 66/32/100 +f 78/34/107 91/43/109 90/35/113 +f 79/42/110 91/43/109 76/41/108 +f 79/42/110 92/48/111 91/43/109 +f 80/30/97 85/31/99 65/6/25 +f 80/30/97 93/50/114 85/31/99 +f 81/29/98 89/49/115 80/30/97 +f 82/38/104 88/51/116 81/29/98 +f 83/20/28 87/52/117 82/38/104 +f 83/20/28 103/54/118 87/52/117 +f 84/16/24 102/53/119 83/20/28 +f 85/31/99 93/50/114 84/55/24 +f 86/46/102 94/47/112 77/44/106 +f 86/46/102 97/59/120 94/47/112 +f 87/52/117 88/51/116 82/38/104 +f 87/52/117 104/60/121 88/51/116 +f 88/51/116 89/49/115 81/29/98 +f 88/51/116 105/61/122 89/49/115 +f 89/49/115 93/50/114 80/30/97 +f 89/49/115 106/62/123 93/50/114 +f 90/35/113 95/36/124 66/32/100 +f 90/35/113 100/63/125 95/36/124 +f 91/43/109 100/63/125 90/35/113 +f 92/48/111 99/64/126 91/43/109 +f 93/50/114 101/56/127 84/55/24 +f 93/50/114 106/62/123 101/56/127 +f 94/47/112 98/65/128 92/48/111 +f 95/36/124 96/37/103 66/32/100 +f 95/36/124 348/68/130 345/69/129 +f 95/36/124 345/69/129 96/37/103 +f 96/58/103 97/59/120 86/46/102 +f 96/58/103 344/78/132 342/72/131 +f 96/58/103 342/72/131 97/59/120 +f 96/58/103 346/79/133 344/78/132 +f 97/59/120 98/65/128 94/47/112 +f 97/59/120 343/80/135 340/74/134 +f 97/59/120 340/74/134 98/65/128 +f 98/65/128 99/64/126 92/48/111 +f 98/65/128 341/75/137 339/76/136 +f 98/65/128 339/76/136 99/64/126 +f 99/64/126 100/63/125 91/43/109 +f 99/64/126 339/76/136 337/81/138 +f 99/64/126 337/81/138 100/63/125 +f 100/63/125 338/83/140 347/82/139 +f 100/63/125 347/82/139 95/36/124 +f 101/57/127 102/53/119 84/16/24 +f 101/56/127 106/62/123 344/78/132 +f 101/56/127 344/78/132 346/79/133 +f 102/53/119 103/54/118 83/20/28 +f 102/53/119 345/69/129 348/68/130 +f 103/54/118 104/60/121 87/52/117 +f 104/60/121 105/61/122 88/51/116 +f 104/60/121 337/81/138 339/76/136 +f 104/60/121 339/76/136 341/75/137 +f 105/61/122 106/62/123 89/49/115 +f 105/61/122 340/74/134 343/80/135 +f 106/62/123 342/72/131 344/78/132 +f 108/84/141 133/86/143 114/85/142 +f 109/87/144 122/89/146 115/88/145 +f 109/90/144 131/92/148 120/91/147 +f 110/93/149 128/95/151 116/94/150 +f 110/96/149 148/98/153 125/97/152 +f 110/96/149 149/99/154 148/98/153 +f 111/100/155 147/102/157 117/101/156 +f 111/103/155 149/99/154 147/104/157 +f 111/103/155 336/106/159 323/105/158 +f 111/103/155 323/105/158 148/98/153 +f 112/107/160 124/109/162 118/108/161 +f 112/110/160 335/112/164 327/111/163 +f 112/110/160 327/111/163 121/113/165 +f 113/114/166 334/116/168 329/115/167 +f 113/114/166 329/115/167 119/117/169 +f 114/85/142 120/118/147 108/84/141 +f 114/85/142 122/89/146 120/118/147 +f 114/85/142 133/86/143 122/89/146 +f 115/88/145 131/119/148 109/87/144 +f 115/88/145 132/120/170 131/119/148 +f 115/88/145 138/121/171 132/120/170 +f 116/94/150 128/95/151 123/122/172 +f 116/94/150 143/124/174 135/123/173 +f 116/94/150 145/125/175 110/93/149 +f 117/101/156 129/127/177 127/126/176 +f 117/101/156 139/128/178 123/122/172 +f 117/101/156 146/130/180 137/129/179 +f 117/101/156 147/102/157 146/130/180 +f 117/101/156 333/132/181 336/131/159 +f 117/101/156 336/131/159 111/100/155 +f 118/108/161 332/134/182 335/133/164 +f 118/108/161 335/133/164 112/107/160 +f 119/117/169 121/135/165 113/114/166 +f 119/117/169 124/109/162 121/135/165 +f 119/117/169 328/137/184 325/136/183 +f 119/117/169 325/136/183 124/109/162 +f 119/117/169 329/115/167 328/137/184 +f 120/118/147 122/89/146 109/87/144 +f 120/91/147 130/139/185 108/138/141 +f 120/91/147 131/92/148 130/139/185 +f 121/135/165 124/109/162 112/107/160 +f 121/113/165 126/141/186 113/140/166 +f 121/113/165 326/142/187 323/105/158 +f 121/113/165 323/105/158 126/141/186 +f 121/113/165 327/111/163 326/142/187 +f 122/89/146 134/143/188 115/88/145 +f 122/89/146 136/144/189 134/143/188 +f 123/122/172 129/127/177 117/101/156 +f 123/122/172 143/124/174 116/94/150 +f 124/109/162 325/136/183 330/145/190 +f 124/109/162 330/145/190 118/108/161 +f 125/146/152 128/95/151 110/93/149 +f 125/97/152 148/98/153 326/142/187 +f 125/97/152 326/142/187 327/111/163 +f 125/97/152 327/111/163 335/112/164 +f 126/141/186 323/105/158 336/106/159 +f 126/147/186 324/148/191 334/116/168 +f 126/147/186 334/116/168 113/114/166 +f 127/126/176 129/127/177 328/137/184 +f 127/126/176 328/137/184 329/115/167 +f 127/126/176 324/148/191 333/132/181 +f 127/126/176 333/132/181 117/101/156 +f 127/126/176 329/115/167 334/116/168 +f 128/95/151 129/127/177 123/122/172 +f 129/127/177 325/136/183 328/137/184 +f 130/149/185 133/86/143 108/84/141 +f 130/149/185 145/125/175 133/86/143 +f 130/139/185 149/99/154 145/150/175 +f 131/92/148 149/99/154 130/139/185 +f 132/120/170 138/121/171 137/129/179 +f 132/120/170 147/102/157 131/119/148 +f 133/86/143 136/144/189 122/89/146 +f 133/86/143 144/151/192 135/123/173 +f 133/86/143 145/125/175 144/151/192 +f 134/143/188 138/121/171 115/88/145 +f 134/143/188 141/152/193 138/121/171 +f 134/143/188 142/153/194 141/152/193 +f 135/123/173 136/144/189 133/86/143 +f 135/123/173 143/124/174 136/144/189 +f 135/123/173 144/151/192 116/94/150 +f 136/144/189 142/153/194 134/143/188 +f 136/144/189 143/124/174 142/153/194 +f 137/129/179 139/128/178 117/101/156 +f 137/129/179 140/154/195 139/128/178 +f 137/129/179 146/130/180 132/120/170 +f 138/121/171 140/154/195 137/129/179 +f 138/121/171 141/152/193 140/154/195 +f 139/128/178 141/152/193 123/122/172 +f 140/154/195 141/152/193 139/128/178 +f 141/152/193 143/124/174 123/122/172 +f 142/153/194 143/124/174 141/152/193 +f 144/151/192 145/125/175 116/94/150 +f 145/150/175 149/99/154 110/96/149 +f 146/130/180 147/102/157 132/120/170 +f 147/104/157 149/99/154 131/92/148 +f 148/98/153 149/99/154 111/103/155 +f 148/98/153 323/105/158 326/142/187 +f 150/84/196 162/118/198 156/85/197 +f 150/138/196 172/139/199 162/91/198 +f 150/84/196 175/86/200 172/149/199 +f 151/87/201 164/89/202 162/118/198 +f 151/87/201 173/119/204 157/88/203 +f 152/93/205 170/95/207 167/146/206 +f 152/93/205 187/125/209 158/94/208 +f 152/96/205 191/99/210 187/150/209 +f 153/103/211 191/99/210 190/98/212 +f 153/100/211 322/155/214 319/132/213 +f 153/100/211 319/132/213 159/101/215 +f 154/107/216 166/109/218 163/135/217 +f 154/107/216 321/157/220 318/156/219 +f 154/107/216 318/156/219 160/108/221 +f 155/114/222 163/135/217 161/117/223 +f 155/140/222 168/141/224 163/113/217 +f 155/114/222 320/159/226 310/158/225 +f 155/114/222 310/158/225 168/147/224 +f 156/85/197 175/86/200 150/84/196 +f 157/88/203 164/89/202 151/87/201 +f 157/88/203 176/143/227 164/89/202 +f 157/88/203 180/121/228 176/143/227 +f 158/94/208 170/95/207 152/93/205 +f 158/94/208 185/124/230 165/122/229 +f 158/94/208 186/151/232 177/123/231 +f 158/94/208 187/125/209 186/151/232 +f 159/101/215 171/127/233 165/122/229 +f 159/101/215 181/128/235 179/129/234 +f 159/101/215 189/102/236 153/100/211 +f 159/101/215 319/132/213 310/158/225 +f 159/101/215 310/158/225 169/126/237 +f 160/108/221 166/109/218 154/107/216 +f 160/108/221 316/145/239 311/136/238 +f 160/108/221 311/136/238 166/109/218 +f 160/108/221 317/160/240 316/145/239 +f 160/108/221 318/156/219 317/160/240 +f 161/117/223 315/161/241 320/159/226 +f 161/117/223 320/159/226 155/114/222 +f 162/118/198 164/89/202 156/85/197 +f 162/91/198 173/92/204 151/90/201 +f 163/135/217 166/109/218 161/117/223 +f 163/113/217 313/162/242 321/112/220 +f 163/113/217 321/112/220 154/110/216 +f 164/89/202 175/86/200 156/85/197 +f 164/89/202 178/144/243 175/86/200 +f 165/122/229 170/95/207 158/94/208 +f 165/122/229 171/127/233 170/95/207 +f 165/122/229 181/128/235 159/101/215 +f 165/122/229 183/152/244 181/128/235 +f 165/122/229 185/124/230 183/152/244 +f 166/109/218 311/136/238 314/163/245 +f 166/109/218 314/163/245 161/117/223 +f 167/146/206 170/95/207 317/160/240 +f 167/146/206 317/160/240 318/156/219 +f 167/97/206 190/98/212 152/96/205 +f 167/146/206 318/156/219 321/157/220 +f 168/141/224 309/164/247 312/142/246 +f 168/141/224 312/142/246 163/113/217 +f 168/147/224 310/158/225 319/132/213 +f 168/147/224 319/132/213 322/155/214 +f 169/126/237 171/127/233 159/101/215 +f 169/126/237 310/158/225 320/159/226 +f 170/95/207 171/127/233 316/145/239 +f 170/95/207 316/145/239 317/160/240 +f 171/127/233 311/136/238 316/145/239 +f 172/139/199 173/92/204 162/91/198 +f 172/139/199 191/99/210 173/92/204 +f 173/119/204 174/120/248 157/88/203 +f 173/119/204 189/102/236 174/120/248 +f 173/92/204 191/99/210 189/104/236 +f 174/120/248 180/121/228 157/88/203 +f 174/120/248 188/130/249 179/129/234 +f 174/120/248 189/102/236 188/130/249 +f 175/86/200 178/144/243 177/123/231 +f 175/86/200 187/125/209 172/149/199 +f 176/143/227 178/144/243 164/89/202 +f 176/143/227 184/153/250 178/144/243 +f 177/123/231 185/124/230 158/94/208 +f 177/123/231 186/151/232 175/86/200 +f 178/144/243 185/124/230 177/123/231 +f 179/129/234 180/121/228 174/120/248 +f 179/129/234 182/154/251 180/121/228 +f 179/129/234 188/130/249 159/101/215 +f 180/121/228 183/152/244 176/143/227 +f 181/128/235 182/154/251 179/129/234 +f 181/128/235 183/152/244 182/154/251 +f 182/154/251 183/152/244 180/121/228 +f 183/152/244 184/153/250 176/143/227 +f 183/152/244 185/124/230 184/153/250 +f 184/153/250 185/124/230 178/144/243 +f 186/151/232 187/125/209 175/86/200 +f 187/150/209 191/99/210 172/139/199 +f 188/130/249 189/102/236 159/101/215 +f 189/104/236 191/99/210 153/103/211 +f 190/98/212 191/99/210 152/96/205 +f 190/98/212 309/164/247 322/106/214 +f 190/98/212 322/106/214 153/103/211 +f 192/165/252 308/167/254 306/166/253 +f 192/165/252 306/166/253 193/168/255 +f 193/168/255 195/170/256 192/169/252 +f 193/168/255 305/172/258 303/171/257 +f 193/168/255 303/171/257 195/170/256 +f 193/168/255 306/166/253 305/172/258 +f 194/173/259 198/175/261 196/174/260 +f 195/176/256 304/178/263 307/177/262 +f 195/176/256 307/177/262 192/165/252 +f 196/179/260 197/181/264 194/180/259 +f 196/174/260 198/175/261 305/172/258 +f 196/174/260 305/172/258 306/166/253 +f 196/174/260 306/166/253 308/167/254 +f 197/182/264 198/175/261 194/173/259 +f 198/175/261 303/171/257 305/172/258 +f 199/165/265 302/184/267 300/183/266 +f 199/165/265 300/183/266 200/168/268 +f 200/168/268 202/170/269 199/169/265 +f 200/168/268 299/186/271 297/185/270 +f 200/168/268 297/185/270 202/170/269 +f 200/168/268 300/183/266 299/186/271 +f 201/173/272 205/175/274 203/174/273 +f 202/176/269 298/188/276 301/187/275 +f 202/176/269 301/187/275 199/165/265 +f 203/179/273 204/181/277 201/180/272 +f 203/174/273 205/175/274 299/186/271 +f 203/174/273 299/186/271 300/183/266 +f 203/174/273 300/183/266 302/184/267 +f 204/182/277 205/175/274 201/173/272 +f 205/175/274 297/185/270 299/186/271 +f 206/165/278 296/190/280 294/189/279 +f 206/165/278 294/189/279 207/168/281 +f 207/168/281 209/170/282 206/169/278 +f 207/168/281 293/192/284 291/191/283 +f 207/168/281 291/191/283 209/170/282 +f 207/168/281 294/189/279 293/192/284 +f 208/173/285 212/175/287 210/174/286 +f 209/176/282 292/194/289 295/193/288 +f 209/176/282 295/193/288 206/165/278 +f 210/179/286 211/181/290 208/180/285 +f 210/174/286 212/175/287 293/192/284 +f 210/174/286 293/192/284 294/189/279 +f 210/174/286 294/189/279 296/190/280 +f 211/182/290 212/175/287 208/173/285 +f 212/175/287 291/191/283 293/192/284 +f 213/169/291 216/170/293 214/168/292 +f 213/165/291 289/196/295 286/195/294 +f 213/165/291 286/195/294 216/176/293 +f 213/165/291 290/197/296 289/196/295 +f 214/168/292 288/198/297 290/197/296 +f 214/168/292 290/197/296 213/165/291 +f 215/180/298 218/181/300 217/179/299 +f 215/173/298 219/175/301 218/182/300 +f 216/170/293 285/200/303 287/199/302 +f 216/170/293 287/199/302 214/168/292 +f 216/170/293 286/201/294 285/200/303 +f 217/174/299 218/181/300 289/196/295 +f 217/174/299 289/196/295 290/197/296 +f 217/174/299 219/175/301 215/173/298 +f 218/182/300 219/175/301 285/200/303 +f 218/182/300 285/200/303 286/201/294 +f 218/181/300 286/195/294 289/196/295 +f 220/169/304 223/170/306 221/168/305 +f 220/165/304 283/203/308 280/202/307 +f 220/165/304 280/202/307 223/176/306 +f 220/165/304 284/204/309 283/203/308 +f 221/168/305 282/205/310 284/204/309 +f 221/168/305 284/204/309 220/165/304 +f 222/180/311 225/181/313 224/179/312 +f 222/173/311 226/175/314 225/182/313 +f 223/170/306 279/207/316 281/206/315 +f 223/170/306 281/206/315 221/168/305 +f 223/170/306 280/208/307 279/207/316 +f 224/174/312 225/181/313 283/203/308 +f 224/174/312 283/203/308 284/204/309 +f 224/174/312 226/175/314 222/173/311 +f 225/182/313 226/175/314 279/207/316 +f 225/182/313 279/207/316 280/208/307 +f 225/181/313 280/202/307 283/203/308 +f 227/169/317 230/170/319 228/168/318 +f 227/165/317 277/210/321 274/209/320 +f 227/165/317 274/209/320 230/176/319 +f 227/165/317 278/211/322 277/210/321 +f 228/168/318 276/212/323 278/211/322 +f 228/168/318 278/211/322 227/165/317 +f 229/180/324 232/181/326 231/179/325 +f 229/173/324 233/175/327 232/182/326 +f 230/170/319 273/214/329 275/213/328 +f 230/170/319 275/213/328 228/168/318 +f 230/170/319 274/215/320 273/214/329 +f 231/174/325 232/181/326 277/210/321 +f 231/174/325 277/210/321 278/211/322 +f 231/174/325 233/175/327 229/173/324 +f 232/182/326 233/175/327 273/214/329 +f 232/182/326 273/214/329 274/215/320 +f 232/181/326 274/209/320 277/210/321 +f 234/2/330 236/216/330 235/3/330 +f 235/3/331 236/216/331 234/2/331 +f 237/2/332 239/216/332 238/3/332 +f 238/3/333 239/216/333 237/2/333 +f 2/2/334 240/216/334 3/3/334 +f 3/3/335 240/216/335 2/2/335 +f 241/2/336 243/216/338 242/217/337 +f 242/217/339 243/216/341 241/2/340 +f 244/2/342 246/216/344 245/217/343 +f 245/217/345 246/216/347 244/2/346 +f 247/2/348 249/216/350 248/217/349 +f 248/217/351 249/216/353 247/2/352 +f 250/1/354 235/3/356 251/218/355 +f 251/218/357 235/3/359 250/1/358 +f 252/1/360 238/3/362 253/218/361 +f 253/218/363 238/3/365 252/1/364 +f 1/1/366 3/3/368 254/218/367 +f 254/218/369 3/3/371 1/1/370 +f 255/1/372 256/3/372 241/2/372 +f 241/2/373 256/3/373 255/1/373 +f 257/1/374 258/3/376 244/2/375 +f 244/2/377 258/3/379 257/1/378 +f 259/1/380 260/3/382 247/2/381 +f 247/2/383 260/3/385 259/1/384 +f 241/2/386 243/216/388 256/3/387 +f 256/3/389 243/216/391 241/2/390 +f 244/2/392 246/216/392 258/3/392 +f 258/3/393 246/216/393 244/2/393 +f 247/2/394 249/216/394 260/3/394 +f 260/3/395 249/216/395 247/2/395 +f 234/2/331 236/216/331 261/217/331 +f 261/217/330 236/216/330 234/2/330 +f 237/2/396 239/216/398 262/217/397 +f 262/217/399 239/216/401 237/2/400 +f 2/2/335 240/216/335 263/217/335 +f 263/217/334 240/216/334 2/2/334 +f 255/1/402 256/3/404 264/218/403 +f 264/218/405 256/3/407 255/1/406 +f 257/1/408 258/3/408 265/218/408 +f 265/218/409 258/3/409 257/1/409 +f 259/1/410 260/3/412 266/218/411 +f 266/218/413 260/3/415 259/1/414 +f 250/1/416 235/3/416 234/2/416 +f 234/2/417 235/3/417 250/1/417 +f 252/1/418 238/3/420 237/2/419 +f 237/2/421 238/3/423 252/1/422 +f 270/17/45 6/17/22 36/55/29 +f 270/17/45 36/55/29 17/6/9 +f 275/213/328 273/214/329 233/175/327 +f 275/213/328 276/212/323 228/168/318 +f 276/212/323 275/213/328 233/175/327 +f 276/212/323 233/175/327 231/174/325 +f 278/211/322 276/212/323 231/174/325 +f 281/206/315 279/207/316 226/175/314 +f 281/206/315 282/205/310 221/168/305 +f 282/205/310 281/206/315 226/175/314 +f 282/205/310 226/175/314 224/174/312 +f 284/204/309 282/205/310 224/174/312 +f 287/199/302 285/200/303 219/175/301 +f 287/199/302 288/198/297 214/168/292 +f 288/198/297 287/199/302 219/175/301 +f 288/198/297 219/175/301 217/174/299 +f 290/197/296 288/198/297 217/174/299 +f 291/191/283 292/219/289 209/170/282 +f 292/219/289 291/191/283 212/175/287 +f 292/219/289 212/175/287 211/182/290 +f 295/193/288 292/194/289 211/181/290 +f 295/193/288 296/190/280 206/165/278 +f 296/190/280 295/193/288 211/181/290 +f 296/190/280 211/181/290 210/174/286 +f 297/185/270 298/220/276 202/170/269 +f 298/220/276 297/185/270 205/175/274 +f 298/220/276 205/175/274 204/182/277 +f 301/187/275 298/188/276 204/181/277 +f 301/187/275 302/184/267 199/165/265 +f 302/184/267 301/187/275 204/181/277 +f 302/184/267 204/181/277 203/174/273 +f 303/171/257 304/221/263 195/170/256 +f 304/221/263 303/171/257 198/175/261 +f 304/221/263 198/175/261 197/182/264 +f 307/177/262 304/178/263 197/181/264 +f 307/177/262 308/167/254 192/165/252 +f 308/167/254 307/177/262 197/181/264 +f 308/167/254 197/181/264 196/174/260 +f 312/142/246 309/164/247 190/98/212 +f 312/142/246 313/162/242 163/113/217 +f 313/162/242 312/142/246 190/98/212 +f 313/162/242 190/98/212 167/97/206 +f 314/163/245 311/136/238 171/127/233 +f 314/163/245 315/161/241 161/117/223 +f 315/161/241 314/163/245 171/127/233 +f 315/161/241 171/127/233 169/126/237 +f 320/159/226 315/161/241 169/126/237 +f 321/112/220 313/162/242 167/97/206 +f 322/106/214 309/164/247 168/141/224 +f 330/145/190 325/136/183 129/127/177 +f 330/145/190 331/160/424 118/108/161 +f 331/160/424 330/145/190 129/127/177 +f 331/160/424 129/127/177 128/95/151 +f 331/160/424 332/134/182 118/108/161 +f 332/134/182 331/160/424 128/95/151 +f 332/134/182 128/95/151 125/146/152 +f 333/132/181 324/148/191 126/147/186 +f 334/116/168 324/148/191 127/126/176 +f 335/133/164 332/134/182 125/146/152 +f 336/131/159 333/132/181 126/147/186 +f 337/81/138 338/83/140 100/63/125 +f 338/83/140 337/81/138 104/60/121 +f 338/83/140 104/60/121 103/54/118 +f 340/74/134 341/75/137 98/65/128 +f 341/75/137 340/74/134 105/61/122 +f 341/75/137 105/61/122 104/60/121 +f 342/72/131 343/80/135 97/59/120 +f 343/80/135 342/72/131 106/62/123 +f 343/80/135 106/62/123 105/61/122 +f 345/69/129 346/70/133 96/37/103 +f 346/70/133 345/69/129 102/53/119 +f 346/70/133 102/53/119 101/57/127 +f 347/82/139 338/83/140 103/54/118 +f 347/82/139 348/68/130 95/36/124 +f 348/68/130 347/82/139 103/54/118 +f 348/68/130 103/54/118 102/53/119 +f 351/76/86 349/77/87 56/60/70 +f 353/75/85 351/76/86 56/60/70 +f 355/73/83 352/74/84 57/61/71 +f 356/71/81 354/72/82 58/62/72 +f 356/71/81 358/79/80 48/58/51 +f 358/79/80 356/71/81 58/62/72 +f 358/79/80 58/62/72 53/56/68 +f 360/68/78 357/69/79 54/53/66 +usemtl default +g Ar_Ropie_D01_Leg_default +s 1 +f 4/222/7 10/222/14 72/222/15 +f 4/222/7 72/222/15 71/222/91 +f 4/222/7 71/222/91 60/222/92 +f 4/222/7 60/222/92 61/222/94 +f 4/222/7 61/222/94 62/222/95 diff --git a/Archer/Archer_finalrig.skeleton b/Archer/Archer_finalrig.skeleton new file mode 100644 index 0000000..0e464a0 Binary files /dev/null and b/Archer/Archer_finalrig.skeleton differ diff --git a/Archer/Archer_finalrig.skeleton.xml b/Archer/Archer_finalrig.skeleton.xml new file mode 100644 index 0000000..fdfb8db --- /dev/null +++ b/Archer/Archer_finalrig.skeleton.xml @@ -0,0 +1,1847 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archer/Archer_finalrig.ugh b/Archer/Archer_finalrig.ugh index 0229026..66ee8b2 100644 Binary files a/Archer/Archer_finalrig.ugh and b/Archer/Archer_finalrig.ugh differ diff --git a/Archer/OgreXMLConverter.log b/Archer/OgreXMLConverter.log new file mode 100644 index 0000000..d38869a --- /dev/null +++ b/Archer/OgreXMLConverter.log @@ -0,0 +1,100 @@ +03:07:19: Creating resource group General +03:07:19: Creating resource group Internal +03:07:19: Creating resource group Autodetect +03:07:19: Registering ResourceManager for type Mesh +03:07:19: Registering ResourceManager for type Material +03:07:19: Registering ResourceManager for type Skeleton +03:07:19: XMLMeshSerializer reading mesh data from D:\Documents\DN\Archer\Archer_finalrig.mesh.xml... +03:07:19: Reading submeshes... +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Reading geometry... +03:07:19: Geometry done... +03:07:19: Reading bone assignments... +03:07:19: Bone assignments done. +03:07:19: Submeshes done. +03:07:19: Skeleton: Loading Archer_finalrig.skeleton +03:07:19: OGRE EXCEPTION(6:FileNotFoundException): Cannot locate resource Archer_finalrig.skeleton in resource group General or any other group. in ResourceGroupManager::openResource at ..\..\..\..\OgreMain\src\OgreResourceGroupManager.cpp (line 753) +03:07:19: Unable to load skeleton Archer_finalrig.skeleton for Mesh conversion. This Mesh will not be animated. You can ignore this message if you are using an offline tool. +03:07:19: XMLMeshSerializer import successful. +03:07:19: Reorganising vertex buffers to automatic layout.. +03:07:19: MeshSerializer writing mesh data to D:\Documents\DN\Archer\Archer_finalrig.mesh... +03:07:19: File header written. +03:07:19: Writing mesh data... +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Writing submesh... +03:07:19: Exporting submesh texture aliases... +03:07:19: Submesh texture aliases exported. +03:07:19: Exporting dedicated geometry bone assignments... +03:07:19: Dedicated geometry bone assignments exported. +03:07:19: Submesh exported. +03:07:19: Exporting skeleton link... +03:07:19: Skeleton link exported. +03:07:19: Exporting bounds information.... +03:07:19: Bounds information exported. +03:07:19: Exporting submesh name table... +03:07:19: Submesh name table exported. +03:07:19: Exporting edge lists... +03:07:19: Edge lists exported +03:07:19: Mesh data exported. +03:07:19: MeshSerializer export successful. +03:07:19: Unregistering ResourceManager for type Skeleton +03:07:19: Unregistering ResourceManager for type Material +03:07:19: Unregistering ResourceManager for type Mesh diff --git a/JmeTests/OpenAL64.dll b/JmeTests/OpenAL64.dll new file mode 100644 index 0000000..6f2a2fe Binary files /dev/null and b/JmeTests/OpenAL64.dll differ diff --git a/JmeTests/assets/.keep b/JmeTests/assets/.keep new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/JmeTests/assets/.keep @@ -0,0 +1 @@ + diff --git a/JmeTests/assets/Interface/.keep b/JmeTests/assets/Interface/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/MatDefs/.keep b/JmeTests/assets/MatDefs/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Materials/.keep b/JmeTests/assets/Materials/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Models/.keep b/JmeTests/assets/Models/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Scenes/.keep b/JmeTests/assets/Scenes/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Shaders/.keep b/JmeTests/assets/Shaders/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Sounds/.keep b/JmeTests/assets/Sounds/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/assets/Textures/.keep b/JmeTests/assets/Textures/.keep new file mode 100644 index 0000000..e69de29 diff --git a/JmeTests/build.xml b/JmeTests/build.xml new file mode 100644 index 0000000..b4275bb --- /dev/null +++ b/JmeTests/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project JmeTests. + + + diff --git a/JmeTests/bulletjme.dll b/JmeTests/bulletjme.dll new file mode 100644 index 0000000..fb9034a Binary files /dev/null and b/JmeTests/bulletjme.dll differ diff --git a/JmeTests/lwjgl64.dll b/JmeTests/lwjgl64.dll new file mode 100644 index 0000000..2c8b93e Binary files /dev/null and b/JmeTests/lwjgl64.dll differ diff --git a/JmeTests/nbproject/build-impl.xml b/JmeTests/nbproject/build-impl.xml new file mode 100644 index 0000000..acc4402 --- /dev/null +++ b/JmeTests/nbproject/build-impl.xml @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JmeTests/nbproject/genfiles.properties b/JmeTests/nbproject/genfiles.properties new file mode 100644 index 0000000..fe4b21c --- /dev/null +++ b/JmeTests/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=3af791c6 +build.xml.script.CRC32=fc2bfcc3 +build.xml.stylesheet.CRC32=8064a381@1.80.1.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=0f706f4a +nbproject/build-impl.xml.script.CRC32=46d1a69a +nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408@1.44.1.45 diff --git a/JmeTests/nbproject/project.properties b/JmeTests/nbproject/project.properties new file mode 100644 index 0000000..2511e8c --- /dev/null +++ b/JmeTests/nbproject/project.properties @@ -0,0 +1,84 @@ +application.title=JME3TestsTemplate +application.vendor=jMonkeyEngine +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/JME3TestsTemplate.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +includes=** +jar.compress=false +javac.classpath=\ + ${libs.jme3-jogg.classpath}:\ + ${libs.jme3-blender.classpath}:\ + ${libs.jme3-networking.classpath}:\ + ${libs.jme3-plugins.classpath}:\ + ${libs.jme3-core.classpath}:\ + ${libs.jme3-desktop.classpath}:\ + ${libs.jme3-lwjgl.classpath}:\ + ${libs.jme3-niftygui.classpath}:\ + ${libs.jme3-effects.classpath}:\ + ${libs.jme3-terrain.classpath}:\ + ${libs.jme3-bullet.classpath}:\ + ${libs.jme3-bullet-native.classpath}:\ + ${libs.jme3-test-data.classpath} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.7 +javac.target=1.7 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api" +jnlp.applet.class=jme3test.awt.TestApplet +jnlp.applet.height=300 +jnlp.applet.width=300 +jnlp.codebase.type=local +jnlp.descriptor=application +jnlp.enabled=false +jnlp.offline-allowed=false +jnlp.signed=false +main.class=jme3test.TestChooser +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src diff --git a/JmeTests/nbproject/project.xml b/JmeTests/nbproject/project.xml new file mode 100644 index 0000000..d12e031 --- /dev/null +++ b/JmeTests/nbproject/project.xml @@ -0,0 +1,13 @@ + + + org.netbeans.modules.java.j2seproject + + + JmeTests + + + + + + + diff --git a/JmeTests/src/META-INF/MANIFEST.MF b/JmeTests/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..59499bc --- /dev/null +++ b/JmeTests/src/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/JmeTests/src/jme3test/TestChooser.java b/JmeTests/src/jme3test/TestChooser.java new file mode 100644 index 0000000..c471960 --- /dev/null +++ b/JmeTests/src/jme3test/TestChooser.java @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test; + +import com.jme3.app.LegacyApplication; +import com.jme3.app.SimpleApplication; +import com.jme3.system.JmeContext; +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Vector; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + + +/** + * Class with a main method that displays a dialog to choose any jME demo to be + * started. + */ +public class TestChooser extends JDialog { + private static final Logger logger = Logger.getLogger(TestChooser.class + .getName()); + + private static final long serialVersionUID = 1L; + + /** + * Only accessed from EDT + */ + private java.util.List selectedClass = null; + private boolean showSetting = true; + + /** + * Constructs a new TestChooser that is initially invisible. + */ + public TestChooser() throws HeadlessException { + super((JFrame) null, "TestChooser"); + /** This listener ends application when window is closed (x button on top right corner of test chooser). + * @see issue#85 https://github.com/jMonkeyEngine/jmonkeyengine/issues/85 + */ + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + } + + /** + * @param classes + * vector that receives the found classes + * @return classes vector, list of all the classes in a given package (must + * be found in classpath). + */ + protected Vector find(String pckgname, boolean recursive, + Vector classes) { + URL url; + + // Translate the package name into an absolute path + String name = pckgname; + if (!name.startsWith("/")) { + name = "/" + name; + } + name = name.replace('.', '/'); + + // Get a File object for the package + // URL url = UPBClassLoader.get().getResource(name); + url = this.getClass().getResource(name); + // URL url = ClassLoader.getSystemClassLoader().getResource(name); + pckgname = pckgname + "."; + + File directory; + try { + directory = new File(URLDecoder.decode(url.getFile(), "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // should never happen + } + + if (directory.exists()) { + logger.fine("Searching for Demo classes in \"" + + directory.getName() + "\"."); + addAllFilesInDirectory(directory, classes, pckgname, recursive); + } else { + try { + // It does not work with the filesystem: we must + // be in the case of a package contained in a jar file. + logger.fine("Searching for Demo classes in \"" + url + "\"."); + URLConnection urlConnection = url.openConnection(); + if (urlConnection instanceof JarURLConnection) { + JarURLConnection conn = (JarURLConnection) urlConnection; + + JarFile jfile = conn.getJarFile(); + Enumeration e = jfile.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = (ZipEntry) e.nextElement(); + Class result = load(entry.getName()); + if (result != null && !classes.contains(result)) { + classes.add(result); + } + } + } + } catch (IOException e) { + logger.logp(Level.SEVERE, this.getClass().toString(), + "find(pckgname, recursive, classes)", "Exception", e); + } catch (Exception e) { + logger.logp(Level.SEVERE, this.getClass().toString(), + "find(pckgname, recursive, classes)", "Exception", e); + } + } + return classes; + } + + /** + * Load a class specified by a file- or entry-name + * + * @param name + * name of a file or entry + * @return class file that was denoted by the name, null if no class or does + * not contain a main method + */ + private Class load(String name) { + if (name.endsWith(".class") + && name.indexOf("Test") >= 0 + && name.indexOf('$') < 0) { + String classname = name.substring(0, name.length() + - ".class".length()); + + if (classname.startsWith("/")) { + classname = classname.substring(1); + } + classname = classname.replace('/', '.'); + + try { + final Class cls = Class.forName(classname); + cls.getMethod("main", new Class[] { String[].class }); + if (!getClass().equals(cls)) { + return cls; + } + } catch (NoClassDefFoundError e) { + // class has unresolved dependencies + return null; + } catch (ClassNotFoundException e) { + // class not in classpath + return null; + } catch (NoSuchMethodException e) { + // class does not have a main method + return null; + } catch (UnsupportedClassVersionError e){ + // unsupported version + return null; + } + } + return null; + } + + /** + * Used to descent in directories, loads classes via {@link #load} + * + * @param directory + * where to search for class files + * @param allClasses + * add loaded classes to this collection + * @param packageName + * current package name for the diven directory + * @param recursive + * true to descent into subdirectories + */ + private void addAllFilesInDirectory(File directory, + Collection allClasses, String packageName, boolean recursive) { + // Get the list of the files contained in the package + File[] files = directory.listFiles(getFileFilter()); + if (files != null) { + for (int i = 0; i < files.length; i++) { + // we are only interested in .class files + if (files[i].isDirectory()) { + if (recursive) { + addAllFilesInDirectory(files[i], allClasses, + packageName + files[i].getName() + ".", true); + } + } else { + Class result = load(packageName + files[i].getName()); + if (result != null && !allClasses.contains(result)) { + allClasses.add(result); + } + } + } + } + } + + /** + * @return FileFilter for searching class files (no inner classes, only + * those with "Test" in the name) + */ + private FileFilter getFileFilter() { + return new FileFilter() { + public boolean accept(File pathname) { + return (pathname.isDirectory() && !pathname.getName().startsWith(".")) + || (pathname.getName().endsWith(".class") + && (pathname.getName().indexOf("Test") >= 0) + && pathname.getName().indexOf('$') < 0); + } + }; + } + + private void startApp(final java.util.List appClass){ + if (appClass == null){ + JOptionPane.showMessageDialog(rootPane, + "Please select a test from the list", + "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + + new Thread(new Runnable(){ + public void run(){ + for (int i = 0; i < appClass.size(); i++) { + Class clazz = (Class)appClass.get(i); + try { + if (LegacyApplication.class.isAssignableFrom(clazz)) { + Object app = clazz.newInstance(); + if (app instanceof SimpleApplication) { + final Method settingMethod = clazz.getMethod("setShowSettings", boolean.class); + settingMethod.invoke(app, showSetting); + } + final Method mainMethod = clazz.getMethod("start"); + mainMethod.invoke(app); + Field contextField = LegacyApplication.class.getDeclaredField("context"); + contextField.setAccessible(true); + JmeContext context = null; + while (context == null) { + context = (JmeContext) contextField.get(app); + Thread.sleep(100); + } + while (!context.isCreated()) { + Thread.sleep(100); + } + while (context.isCreated()) { + Thread.sleep(100); + } + } else { + final Method mainMethod = clazz.getMethod("main", (new String[0]).getClass()); + mainMethod.invoke(clazz, new Object[]{new String[0]}); + } + // wait for destroy + System.gc(); + } catch (IllegalAccessException ex) { + logger.log(Level.SEVERE, "Cannot access constructor: "+clazz.getName(), ex); + } catch (IllegalArgumentException ex) { + logger.log(Level.SEVERE, "main() had illegal argument: "+clazz.getName(), ex); + } catch (InvocationTargetException ex) { + logger.log(Level.SEVERE, "main() method had exception: "+clazz.getName(), ex); + } catch (InstantiationException ex) { + logger.log(Level.SEVERE, "Failed to create app: "+clazz.getName(), ex); + } catch (NoSuchMethodException ex){ + logger.log(Level.SEVERE, "Test class doesn't have main method: "+clazz.getName(), ex); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Cannot start test: "+clazz.getName(), ex); + ex.printStackTrace(); + } + } + } + }).start(); + } + + /** + * Code to create components and action listeners. + * + * @param classes + * what Classes to show in the list box + */ + private void setup(Vector classes) { + final JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(mainPanel, BorderLayout.CENTER); + mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + + final FilteredJList list = new FilteredJList(); + list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + DefaultListModel model = new DefaultListModel(); + for (Class c : classes) { + model.addElement(c); + } + list.setModel(model); + + mainPanel.add(createSearchPanel(list), BorderLayout.NORTH); + mainPanel.add(new JScrollPane(list), BorderLayout.CENTER); + + list.getSelectionModel().addListSelectionListener( + new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + selectedClass = list.getSelectedValuesList(); + } + }); + list.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && selectedClass != null) { + startApp(selectedClass); + } + } + }); + list.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + startApp(selectedClass); + } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + dispose(); + } + } + }); + + final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + mainPanel.add(buttonPanel, BorderLayout.PAGE_END); + + final JButton okButton = new JButton("Ok"); + okButton.setMnemonic('O'); + buttonPanel.add(okButton); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + startApp(selectedClass); + } + }); + + final JButton cancelButton = new JButton("Cancel"); + cancelButton.setMnemonic('C'); + buttonPanel.add(cancelButton); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + + pack(); + center(); + } + + private class FilteredJList extends JList { + private static final long serialVersionUID = 1L; + + private String filter; + private ListModel originalModel; + + public void setModel(ListModel m) { + originalModel = m; + super.setModel(m); + } + + private void update() { + if (filter == null || filter.length() == 0) { + super.setModel(originalModel); + } + + DefaultListModel v = new DefaultListModel(); + for (int i = 0; i < originalModel.getSize(); i++) { + Object o = originalModel.getElementAt(i); + String s = String.valueOf(o).toLowerCase(); + if (s.contains(filter)) { + v.addElement(o); + } + } + super.setModel(v); + if (v.getSize() == 1) { + setSelectedIndex(0); + } + revalidate(); + } + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter.toLowerCase(); + update(); + } + } + + /** + * center the frame. + */ + private void center() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension frameSize = this.getSize(); + if (frameSize.height > screenSize.height) { + frameSize.height = screenSize.height; + } + if (frameSize.width > screenSize.width) { + frameSize.width = screenSize.width; + } + this.setLocation((screenSize.width - frameSize.width) / 2, + (screenSize.height - frameSize.height) / 2); + } + + /** + * Start the chooser. + * + * @param args + * command line parameters + */ + public static void main(final String[] args) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + } + new TestChooser().start(args); + } + + protected void start(String[] args) { + final Vector classes = new Vector(); + logger.fine("Composing Test list..."); + addDisplayedClasses(classes); + setup(classes); + Class cls; + setVisible(true); + } + + protected void addDisplayedClasses(Vector classes) { + find("jme3test", true, classes); + } + + private JPanel createSearchPanel(final FilteredJList classes) { + JPanel search = new JPanel(); + search.setLayout(new BorderLayout()); + search.add(new JLabel("Choose a Demo to start: Find: "), + BorderLayout.WEST); + final javax.swing.JTextField jtf = new javax.swing.JTextField(); + jtf.getDocument().addDocumentListener(new DocumentListener() { + public void removeUpdate(DocumentEvent e) { + classes.setFilter(jtf.getText()); + } + + public void insertUpdate(DocumentEvent e) { + classes.setFilter(jtf.getText()); + } + + public void changedUpdate(DocumentEvent e) { + classes.setFilter(jtf.getText()); + } + }); + jtf.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + selectedClass = classes.getSelectedValuesList(); + startApp(selectedClass); + } + }); + final JCheckBox showSettingCheck = new JCheckBox("Show Setting"); + showSettingCheck.setSelected(true); + showSettingCheck.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showSetting = showSettingCheck.isSelected(); + } + }); + jtf.setPreferredSize(new Dimension(100, 25)); + search.add(jtf, BorderLayout.CENTER); + search.add(showSettingCheck, BorderLayout.EAST); + return search; + } +} diff --git a/JmeTests/src/jme3test/animation/SubtitleTrack.java b/JmeTests/src/jme3test/animation/SubtitleTrack.java new file mode 100644 index 0000000..d1d4151 --- /dev/null +++ b/JmeTests/src/jme3test/animation/SubtitleTrack.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.animation; + +import com.jme3.cinematic.events.GuiEvent; +import de.lessvoid.nifty.Nifty; +import de.lessvoid.nifty.elements.render.TextRenderer; + +/** + * + * @author Nehon + */ +public class SubtitleTrack extends GuiEvent{ + private String text=""; + + public SubtitleTrack(Nifty nifty, String screen,float initialDuration, String text) { + super(nifty, screen, initialDuration); + this.text=text; + } + + @Override + public void onPlay() { + super.onPlay(); + nifty.getScreen(screen).findElementById("text") + .getRenderer(TextRenderer.class).setText(text); + } + + + + + + + + +} diff --git a/JmeTests/src/jme3test/animation/TestCameraMotionPath.java b/JmeTests/src/jme3test/animation/TestCameraMotionPath.java new file mode 100644 index 0000000..baeb41a --- /dev/null +++ b/JmeTests/src/jme3test/animation/TestCameraMotionPath.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.animation; + +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.cinematic.MotionPath; +import com.jme3.cinematic.MotionPathListener; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.font.BitmapText; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Spline.SplineType; +import com.jme3.math.Vector3f; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.CameraControl.ControlDirection; +import com.jme3.scene.shape.Box; + +public class TestCameraMotionPath extends SimpleApplication { + + private Spatial teapot; + private boolean active = true; + private boolean playing = false; + private MotionPath path; + private MotionEvent cameraMotionControl; + private ChaseCamera chaser; + private CameraNode camNode; + + public static void main(String[] args) { + TestCameraMotionPath app = new TestCameraMotionPath(); + app.start(); + } + + @Override + public void simpleInitApp() { + createScene(); + cam.setLocation(new Vector3f(8.4399185f, 11.189463f, 14.267577f)); + camNode = new CameraNode("Motion cam", cam); + camNode.setControlDir(ControlDirection.SpatialToCamera); + camNode.setEnabled(false); + path = new MotionPath(); + path.setCycle(true); + path.addWayPoint(new Vector3f(20, 3, 0)); + path.addWayPoint(new Vector3f(0, 3, 20)); + path.addWayPoint(new Vector3f(-20, 3, 0)); + path.addWayPoint(new Vector3f(0, 3, -20)); + path.setCurveTension(0.83f); + path.enableDebugShape(assetManager, rootNode); + + cameraMotionControl = new MotionEvent(camNode, path); + cameraMotionControl.setLoopMode(LoopMode.Loop); + //cameraMotionControl.setDuration(15f); + cameraMotionControl.setLookAt(teapot.getWorldTranslation(), Vector3f.UNIT_Y); + cameraMotionControl.setDirectionType(MotionEvent.Direction.LookAt); + + rootNode.attachChild(camNode); + + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + final BitmapText wayPointsText = new BitmapText(guiFont, false); + wayPointsText.setSize(guiFont.getCharSet().getRenderedSize()); + + guiNode.attachChild(wayPointsText); + + path.addListener(new MotionPathListener() { + + public void onWayPointReach(MotionEvent control, int wayPointIndex) { + if (path.getNbWayPoints() == wayPointIndex + 1) { + wayPointsText.setText(control.getSpatial().getName() + " Finish!!! "); + } else { + wayPointsText.setText(control.getSpatial().getName() + " Reached way point " + wayPointIndex); + } + wayPointsText.setLocalTranslation((cam.getWidth() - wayPointsText.getLineWidth()) / 2, cam.getHeight(), 0); + } + }); + + flyCam.setEnabled(false); + chaser = new ChaseCamera(cam, teapot); + chaser.registerWithInput(inputManager); + chaser.setSmoothMotion(true); + chaser.setMaxDistance(50); + chaser.setDefaultDistance(50); + initInputs(); + + } + + private void createScene() { + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 1f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Black); + mat.setColor("Diffuse", ColorRGBA.DarkGray); + mat.setColor("Specular", ColorRGBA.White.mult(0.6f)); + Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Gray); + matSoil.setColor("Specular", ColorRGBA.Black); + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalScale(3); + teapot.setMaterial(mat); + + + + rootNode.attachChild(teapot); + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -1, 0); + soil.setMaterial(matSoil); + rootNode.attachChild(soil); + DirectionalLight light = new DirectionalLight(); + light.setDirection(new Vector3f(0, -1, 0).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + } + + private void initInputs() { + inputManager.addMapping("display_hidePath", new KeyTrigger(KeyInput.KEY_P)); + inputManager.addMapping("SwitchPathInterpolation", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addMapping("tensionUp", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("tensionDown", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("play_stop", new KeyTrigger(KeyInput.KEY_SPACE)); + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("display_hidePath") && keyPressed) { + if (active) { + active = false; + path.disableDebugShape(); + } else { + active = true; + path.enableDebugShape(assetManager, rootNode); + } + } + if (name.equals("play_stop") && keyPressed) { + if (playing) { + playing = false; + cameraMotionControl.stop(); + chaser.setEnabled(true); + camNode.setEnabled(false); + } else { + playing = true; + chaser.setEnabled(false); + camNode.setEnabled(true); + cameraMotionControl.play(); + } + } + + if (name.equals("SwitchPathInterpolation") && keyPressed) { + if (path.getPathSplineType() == SplineType.CatmullRom) { + path.setPathSplineType(SplineType.Linear); + } else { + path.setPathSplineType(SplineType.CatmullRom); + } + } + + if (name.equals("tensionUp") && keyPressed) { + path.setCurveTension(path.getCurveTension() + 0.1f); + System.err.println("Tension : " + path.getCurveTension()); + } + if (name.equals("tensionDown") && keyPressed) { + path.setCurveTension(path.getCurveTension() - 0.1f); + System.err.println("Tension : " + path.getCurveTension()); + } + + + } + }; + + inputManager.addListener(acl, "display_hidePath", "play_stop", "SwitchPathInterpolation", "tensionUp", "tensionDown"); + + } +} diff --git a/JmeTests/src/jme3test/animation/TestCinematic.java b/JmeTests/src/jme3test/animation/TestCinematic.java new file mode 100644 index 0000000..01c0952 --- /dev/null +++ b/JmeTests/src/jme3test/animation/TestCinematic.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.animation; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimationFactory; +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.cinematic.Cinematic; +import com.jme3.cinematic.MotionPath; +import com.jme3.cinematic.PlayState; +import com.jme3.cinematic.events.*; +import com.jme3.font.BitmapText; +import com.jme3.input.ChaseCamera; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.niftygui.NiftyJmeDisplay; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.FadeFilter; +import com.jme3.renderer.Caps; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import de.lessvoid.nifty.Nifty; + +public class TestCinematic extends SimpleApplication { + + private Spatial model; + private Spatial teapot; + private MotionPath path; + private MotionEvent cameraMotionEvent; + private Cinematic cinematic; + private ChaseCamera chaseCam; + private FilterPostProcessor fpp; + private FadeFilter fade; + private float time = 0; + + public static void main(String[] args) { + TestCinematic app = new TestCinematic(); + app.start(); + + + + } + + @Override + public void simpleInitApp() { + //just some text + NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(getAssetManager(), + getInputManager(), + getAudioRenderer(), + getGuiViewPort()); + Nifty nifty; + nifty = niftyDisplay.getNifty(); + nifty.fromXmlWithoutStartScreen("Interface/Nifty/CinematicTest.xml"); + getGuiViewPort().addProcessor(niftyDisplay); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + final BitmapText text = new BitmapText(guiFont, false); + text.setSize(guiFont.getCharSet().getRenderedSize()); + text.setText("Press enter to play/pause cinematic"); + text.setLocalTranslation((cam.getWidth() - text.getLineWidth()) / 2, cam.getHeight(), 0); + guiNode.attachChild(text); + + + createScene(); + + cinematic = new Cinematic(rootNode, 20); + stateManager.attach(cinematic); + + createCameraMotion(); + + //creating spatial animation for the teapot + AnimationFactory factory = new AnimationFactory(20, "teapotAnim"); + factory.addTimeTranslation(0, new Vector3f(10, 0, 10)); + factory.addTimeTranslation(20, new Vector3f(10, 0, -10)); + factory.addTimeScale(10, new Vector3f(4, 4, 4)); + factory.addTimeScale(20, new Vector3f(1, 1, 1)); + factory.addTimeRotationAngles(20, 0, 4 * FastMath.TWO_PI, 0); + AnimControl control = new AnimControl(); + control.addAnim(factory.buildAnimation()); + teapot.addControl(control); + + //fade in + cinematic.addCinematicEvent(0, new FadeEvent(true)); + // cinematic.activateCamera(0, "aroundCam"); + cinematic.addCinematicEvent(0, new AnimationEvent(teapot, "teapotAnim", LoopMode.DontLoop)); + cinematic.addCinematicEvent(0, cameraMotionEvent); + cinematic.addCinematicEvent(0, new SoundEvent("Sound/Environment/Nature.ogg", LoopMode.Loop)); + cinematic.addCinematicEvent(3f, new SoundEvent("Sound/Effects/kick.wav")); + cinematic.addCinematicEvent(3, new SubtitleTrack(nifty, "start", 3, "jMonkey engine really kicks A...")); + cinematic.addCinematicEvent(5.1f, new SoundEvent("Sound/Effects/Beep.ogg", 1)); + cinematic.addCinematicEvent(2, new AnimationEvent(model, "Walk", LoopMode.Loop)); + cinematic.activateCamera(0, "topView"); + // cinematic.activateCamera(10, "aroundCam"); + + //fade out + cinematic.addCinematicEvent(19, new FadeEvent(false)); +// cinematic.addCinematicEvent(19, new AbstractCinematicEvent() { +// +// @Override +// public void onPlay() { +// fade.setDuration(1f / cinematic.getSpeed()); +// fade.fadeOut(); +// +// } +// +// @Override +// public void onUpdate(float tpf) { +// } +// +// @Override +// public void onStop() { +// } +// +// @Override +// public void onPause() { +// } +// }); + + cinematic.addListener(new CinematicEventListener() { + + public void onPlay(CinematicEvent cinematic) { + chaseCam.setEnabled(false); + System.out.println("play"); + } + + public void onPause(CinematicEvent cinematic) { + System.out.println("pause"); + } + + public void onStop(CinematicEvent cinematic) { + chaseCam.setEnabled(true); + fade.setValue(1); + System.out.println("stop"); + } + }); + + //cinematic.setSpeed(2); + flyCam.setEnabled(false); + chaseCam = new ChaseCamera(cam, model, inputManager); + initInputs(); + + } + + private void createCameraMotion() { + + CameraNode camNode = cinematic.bindCamera("topView", cam); + camNode.setLocalTranslation(new Vector3f(0, 50, 0)); + camNode.lookAt(teapot.getLocalTranslation(), Vector3f.UNIT_Y); + + CameraNode camNode2 = cinematic.bindCamera("aroundCam", cam); + path = new MotionPath(); + path.setCycle(true); + path.addWayPoint(new Vector3f(20, 3, 0)); + path.addWayPoint(new Vector3f(0, 3, 20)); + path.addWayPoint(new Vector3f(-20, 3, 0)); + path.addWayPoint(new Vector3f(0, 3, -20)); + path.setCurveTension(0.83f); + cameraMotionEvent = new MotionEvent(camNode2, path); + cameraMotionEvent.setLoopMode(LoopMode.Loop); + cameraMotionEvent.setLookAt(model.getWorldTranslation(), Vector3f.UNIT_Y); + cameraMotionEvent.setDirectionType(MotionEvent.Direction.LookAt); + + } + + private void createScene() { + + model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + model.center(); + model.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(model); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Cyan); + + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(10, 0, 10); + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(teapot); + + Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Green); + matSoil.setColor("Specular", ColorRGBA.Black); + + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -6, 0); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(soil); + DirectionalLight light = new DirectionalLight(); + light.setDirection(new Vector3f(0, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + + fpp = new FilterPostProcessor(assetManager); + fade = new FadeFilter(); + fpp.addFilter(fade); + + if (renderer.getCaps().contains(Caps.GLSL100)) { + DirectionalLightShadowRenderer dlsr + = new DirectionalLightShadowRenderer(assetManager, 512, 1); + dlsr.setLight(light); + dlsr.setShadowIntensity(0.4f); + viewPort.addProcessor(dlsr); + viewPort.addProcessor(fpp); + } + } + + private void initInputs() { + inputManager.addMapping("togglePause", new KeyTrigger(keyInput.KEY_RETURN)); + inputManager.addMapping("navFwd", new KeyTrigger(keyInput.KEY_RIGHT)); + inputManager.addMapping("navBack", new KeyTrigger(keyInput.KEY_LEFT)); + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("togglePause") && keyPressed) { + if (cinematic.getPlayState() == PlayState.Playing) { + cinematic.pause(); + time = cinematic.getTime(); + } else { + cinematic.play(); + } + } + + if (cinematic.getPlayState() != PlayState.Playing) { + if (name.equals("navFwd") && keyPressed) { + time += 0.25; + FastMath.clamp(time, 0, cinematic.getInitialDuration()); + cinematic.setTime(time); + } + if (name.equals("navBack") && keyPressed) { + time -= 0.25; + FastMath.clamp(time, 0, cinematic.getInitialDuration()); + cinematic.setTime(time); + } + + } + } + }; + inputManager.addListener(acl, "togglePause", "navFwd", "navBack"); + } + + private class FadeEvent extends AbstractCinematicEvent { + + boolean in = true; + float value = 0; + + public FadeEvent(boolean in) { + super(1); + this.in = in; + value = in ? 0 : 1; + } + + @Override + public void onPlay() { + + fade.setDuration(1f / cinematic.getSpeed()); + if (in) { + fade.fadeIn(); + } else { + fade.fadeOut(); + } + fade.setValue(value); + + } + + @Override + public void setTime(float time) { + super.setTime(time); + if (time >= fade.getDuration()) { + value = in ? 1 : 0; + fade.setValue(value); + } else { + value = time; + if (in) { + fade.setValue(time / cinematic.getSpeed()); + } else { + fade.setValue(1 - time / cinematic.getSpeed()); + } + } + } + + @Override + public void onUpdate(float tpf) { + } + + @Override + public void onStop() { + } + + @Override + public void onPause() { + value = fade.getValue(); + fade.pause(); + } + } +} diff --git a/JmeTests/src/jme3test/animation/TestJaime.java b/JmeTests/src/jme3test/animation/TestJaime.java new file mode 100644 index 0000000..cfb1106 --- /dev/null +++ b/JmeTests/src/jme3test/animation/TestJaime.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.animation; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimationFactory; +import com.jme3.animation.LoopMode; +import com.jme3.app.DebugKeysAppState; +import com.jme3.app.FlyCamAppState; +import com.jme3.app.ResetStatsState; +import com.jme3.app.SimpleApplication; +import com.jme3.app.StatsAppState; +import com.jme3.cinematic.Cinematic; +import com.jme3.cinematic.MotionPath; +import com.jme3.cinematic.PlayState; +import com.jme3.cinematic.events.AnimationEvent; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.FXAAFilter; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Quad; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.SpotLightShadowRenderer; + +/** + * + * @author Nehon + */ +public class TestJaime extends SimpleApplication { + + + Cinematic cinematic; + + public static void main(String... argv){ + TestJaime app = new TestJaime(); + app.start(); + } + + + + @Override + public void simpleInitApp() { + stateManager.detach(stateManager.getState(FlyCamAppState.class)); + stateManager.detach(stateManager.getState(ResetStatsState.class)); + stateManager.detach(stateManager.getState(DebugKeysAppState.class)); + stateManager.detach(stateManager.getState(StatsAppState.class)); + final Node jaime = LoadModel(); + + setupLights(); + setupCamera(); + setupFloor(); + setupCinematic(jaime); + setupInput(); + } + + public Node LoadModel() { + Node jaime = (Node)assetManager.loadModel("Models/Jaime/Jaime.j3o"); + jaime.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(jaime); + return jaime; + } + + public void setupLights() { + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(0.1f, 0.1f, 0.1f, 1)); + rootNode.addLight(al); + + SpotLight sl = new SpotLight(); + sl.setColor(ColorRGBA.White.mult(1.0f)); + sl.setPosition(new Vector3f(1.2074411f, 10.6868908f, 4.1489987f)); + sl.setDirection(sl.getPosition().mult(-1)); + sl.setSpotOuterAngle(0.1f); + sl.setSpotInnerAngle(0.004f); + rootNode.addLight(sl); + + //pointlight to fake indirect light coming from the ground + PointLight pl = new PointLight(); + pl.setColor(ColorRGBA.White.mult(1.5f)); + pl.setPosition(new Vector3f(0, 0, 1)); + pl.setRadius(2); + rootNode.addLight(pl); + + SpotLightShadowRenderer shadows = new SpotLightShadowRenderer(assetManager, 1024); + shadows.setLight(sl); + shadows.setShadowIntensity(0.3f); + shadows.setEdgeFilteringMode(EdgeFilteringMode.PCF8); + viewPort.addProcessor(shadows); + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + SSAOFilter filter = new SSAOFilter(0.10997847f,0.440001f,0.39999998f,-0.008000026f);; + fpp.addFilter(filter); + fpp.addFilter(new FXAAFilter()); + fpp.addFilter(new FXAAFilter()); + + viewPort.addProcessor(fpp); + } + + public void setupCamera() { + flyCam.setEnabled(false); + } + + public void setupCinematic(final Node jaime) { + cinematic = new Cinematic(rootNode, 60); + stateManager.attach(cinematic); + + jaime.move(0, 0, -3); + AnimationFactory af = new AnimationFactory(0.7f, "JumpForward"); + af.addTimeTranslation(0, new Vector3f(0, 0, -3)); + af.addTimeTranslation(0.35f, new Vector3f(0, 1, -1.5f)); + af.addTimeTranslation(0.7f, new Vector3f(0, 0, 0)); + jaime.getControl(AnimControl.class).addAnim(af.buildAnimation()); + + cinematic.enqueueCinematicEvent(new AnimationEvent(jaime, "Idle",3, LoopMode.DontLoop)); + float jumpStart = cinematic.enqueueCinematicEvent(new AnimationEvent(jaime, "JumpStart", LoopMode.DontLoop)); + cinematic.addCinematicEvent(jumpStart+0.2f, new AnimationEvent(jaime, "JumpForward", LoopMode.DontLoop,1)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "JumpEnd", LoopMode.DontLoop)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "Punches", LoopMode.DontLoop)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "SideKick", LoopMode.DontLoop)); + float camStart = cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "Taunt", LoopMode.DontLoop)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "Idle",1, LoopMode.DontLoop)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "Wave", LoopMode.DontLoop)); + cinematic.enqueueCinematicEvent( new AnimationEvent(jaime, "Idle", LoopMode.DontLoop)); + + CameraNode camNode = cinematic.bindCamera("cam", cam); + camNode.setLocalTranslation(new Vector3f(1.1f, 1.2f, 2.9f)); + camNode.lookAt(new Vector3f(0, 0.5f, 0), Vector3f.UNIT_Y); + + MotionPath path = new MotionPath(); + path.addWayPoint(new Vector3f(1.1f, 1.2f, 2.9f)); + path.addWayPoint(new Vector3f(0f, 1.2f, 3.0f)); + path.addWayPoint(new Vector3f(-1.1f, 1.2f, 2.9f)); + path.enableDebugShape(assetManager, rootNode); + path.setCurveTension(0.8f); + + MotionEvent camMotion = new MotionEvent(camNode, path,6); + camMotion.setDirectionType(MotionEvent.Direction.LookAt); + camMotion.setLookAt(new Vector3f(0, 0.5f, 0), Vector3f.UNIT_Y); + cinematic.addCinematicEvent(camStart, camMotion); + cinematic.activateCamera(0, "cam"); + + + cinematic.fitDuration(); + cinematic.setSpeed(1.2f); + cinematic.setLoopMode(LoopMode.Loop); + cinematic.play(); + } + + public void setupFloor() { + Quad q = new Quad(20, 20); + q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(10)); + Geometry geom = new Geometry("floor", q); + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setColor("Diffuse", ColorRGBA.White); + mat.setColor("Specular", ColorRGBA.White); + mat.setColor("Ambient", ColorRGBA.Black); + mat.setBoolean("UseMaterialColors", true); + mat.setFloat("Shininess", 0); + geom.setMaterial(mat); + + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.center(); + geom.setShadowMode(RenderQueue.ShadowMode.Receive); + rootNode.attachChild(geom); + } + + public void setupInput() { + inputManager.addMapping("start", new KeyTrigger(KeyInput.KEY_PAUSE)); + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if(name.equals("start") && isPressed){ + if(cinematic.getPlayState() != PlayState.Playing){ + cinematic.play(); + }else{ + cinematic.pause(); + } + } + } + }, "start"); + } + + + +} diff --git a/JmeTests/src/jme3test/animation/TestMotionPath.java b/JmeTests/src/jme3test/animation/TestMotionPath.java new file mode 100644 index 0000000..51268b6 --- /dev/null +++ b/JmeTests/src/jme3test/animation/TestMotionPath.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.animation; + +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.cinematic.MotionPath; +import com.jme3.cinematic.MotionPathListener; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.cinematic.events.MotionEvent; +import com.jme3.font.BitmapText; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Spline.SplineType; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; + +public class TestMotionPath extends SimpleApplication { + + private Spatial teapot; + private boolean active = true; + private boolean playing = false; + private MotionPath path; + private MotionEvent motionControl; + + public static void main(String[] args) { + TestMotionPath app = new TestMotionPath(); + app.start(); + } + + @Override + public void simpleInitApp() { + createScene(); + cam.setLocation(new Vector3f(8.4399185f, 11.189463f, 14.267577f)); + path = new MotionPath(); + path.addWayPoint(new Vector3f(10, 3, 0)); + path.addWayPoint(new Vector3f(10, 3, 10)); + path.addWayPoint(new Vector3f(-40, 3, 10)); + path.addWayPoint(new Vector3f(-40, 3, 0)); + path.addWayPoint(new Vector3f(-40, 8, 0)); + path.addWayPoint(new Vector3f(10, 8, 0)); + path.addWayPoint(new Vector3f(10, 8, 10)); + path.addWayPoint(new Vector3f(15, 8, 10)); + path.enableDebugShape(assetManager, rootNode); + + motionControl = new MotionEvent(teapot,path); + motionControl.setDirectionType(MotionEvent.Direction.PathAndRotation); + motionControl.setRotation(new Quaternion().fromAngleNormalAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y)); + motionControl.setInitialDuration(10f); + motionControl.setSpeed(2f); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + final BitmapText wayPointsText = new BitmapText(guiFont, false); + wayPointsText.setSize(guiFont.getCharSet().getRenderedSize()); + + guiNode.attachChild(wayPointsText); + + path.addListener(new MotionPathListener() { + + public void onWayPointReach(MotionEvent control, int wayPointIndex) { + if (path.getNbWayPoints() == wayPointIndex + 1) { + wayPointsText.setText(control.getSpatial().getName() + "Finished!!! "); + } else { + wayPointsText.setText(control.getSpatial().getName() + " Reached way point " + wayPointIndex); + } + wayPointsText.setLocalTranslation((cam.getWidth() - wayPointsText.getLineWidth()) / 2, cam.getHeight(), 0); + } + }); + + flyCam.setEnabled(false); + ChaseCamera chaser = new ChaseCamera(cam, teapot); +// motionControl.setSpeed(-3f); +// motionControl.setLoopMode(LoopMode.Loop); +// path.setCycle(true); + + + // chaser.setEnabled(false); + chaser.registerWithInput(inputManager); + initInputs(); + + } + + private void createScene() { + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 1f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Black); + mat.setColor("Diffuse", ColorRGBA.DarkGray); + mat.setColor("Specular", ColorRGBA.White.mult(0.6f)); + Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Black); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Black); + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setName("Teapot"); + teapot.setLocalScale(3); + teapot.setMaterial(mat); + + + rootNode.attachChild(teapot); + Geometry soil = new Geometry("soil", new Box(50, 1, 50)); + soil.setLocalTranslation(0, -1, 0); + soil.setMaterial(matSoil); + + rootNode.attachChild(soil); + DirectionalLight light = new DirectionalLight(); + light.setDirection(new Vector3f(0, -1, 0).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + } + + private void initInputs() { + inputManager.addMapping("display_hidePath", new KeyTrigger(KeyInput.KEY_P)); + inputManager.addMapping("SwitchPathInterpolation", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addMapping("tensionUp", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("tensionDown", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("play_stop", new KeyTrigger(KeyInput.KEY_SPACE)); + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("display_hidePath") && keyPressed) { + if (active) { + active = false; + path.disableDebugShape(); + } else { + active = true; + path.enableDebugShape(assetManager, rootNode); + } + } + if (name.equals("play_stop") && keyPressed) { + if (playing) { + playing = false; + motionControl.stop(); + } else { + playing = true; + motionControl.play(); + } + } + + if (name.equals("SwitchPathInterpolation") && keyPressed) { + if (path.getPathSplineType() == SplineType.CatmullRom){ + path.setPathSplineType(SplineType.Linear); + } else { + path.setPathSplineType(SplineType.CatmullRom); + } + } + + if (name.equals("tensionUp") && keyPressed) { + path.setCurveTension(path.getCurveTension() + 0.1f); + System.err.println("Tension : " + path.getCurveTension()); + } + if (name.equals("tensionDown") && keyPressed) { + path.setCurveTension(path.getCurveTension() - 0.1f); + System.err.println("Tension : " + path.getCurveTension()); + } + + + } + }; + + inputManager.addListener(acl, "display_hidePath", "play_stop", "SwitchPathInterpolation", "tensionUp", "tensionDown"); + + } +} diff --git a/JmeTests/src/jme3test/app/TestAppStateLifeCycle.java b/JmeTests/src/jme3test/app/TestAppStateLifeCycle.java new file mode 100644 index 0000000..ebca776 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestAppStateLifeCycle.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.app.Application; +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.AbstractAppState; +import com.jme3.app.state.AppStateManager; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + + +/** + * Tests the app state lifecycles. + * + * @author Paul Speed + */ +public class TestAppStateLifeCycle extends SimpleApplication { + + public static void main(String[] args){ + TestAppStateLifeCycle app = new TestAppStateLifeCycle(); + app.start(); + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + System.out.println("Attaching test state."); + stateManager.attach(new TestState()); + } + + @Override + public void simpleUpdate(float tpf) { + + if(stateManager.getState(TestState.class) != null) { + System.out.println("Detaching test state."); + stateManager.detach(stateManager.getState(TestState.class)); + System.out.println("Done"); + } + } + + public class TestState extends AbstractAppState { + + @Override + public void initialize(AppStateManager stateManager, Application app) { + super.initialize(stateManager, app); + System.out.println("Initialized"); + } + + @Override + public void stateAttached(AppStateManager stateManager) { + super.stateAttached(stateManager); + System.out.println("Attached"); + } + + @Override + public void update(float tpf) { + super.update(tpf); + System.out.println("update"); + } + + @Override + public void render(RenderManager rm) { + super.render(rm); + System.out.println("render"); + } + + @Override + public void postRender() { + super.postRender(); + System.out.println("postRender"); + } + + @Override + public void stateDetached(AppStateManager stateManager) { + super.stateDetached(stateManager); + System.out.println("Detached"); + } + + @Override + public void cleanup() { + super.cleanup(); + System.out.println("Cleanup"); + } + + } +} diff --git a/JmeTests/src/jme3test/app/TestApplication.java b/JmeTests/src/jme3test/app/TestApplication.java new file mode 100644 index 0000000..1559318 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestApplication.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.app.LegacyApplication; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext.Type; + +/** + * Test LegacyApplication functionality, such as create, restart, destroy, etc. + * @author Kirill + */ +public class TestApplication { + + public static void main(String[] args) throws InterruptedException{ + System.out.println("Creating application.."); + LegacyApplication app = new LegacyApplication(); + System.out.println("Starting application in LWJGL mode.."); + app.start(); + System.out.println("Waiting 5 seconds"); + Thread.sleep(5000); + System.out.println("Closing application.."); + app.stop(); + + Thread.sleep(2000); + System.out.println("Starting in fullscreen mode"); + app = new LegacyApplication(); + AppSettings settings = new AppSettings(true); + settings.setFullscreen(true); + settings.setResolution(-1,-1); // current width/height + app.setSettings(settings); + app.start(); + Thread.sleep(5000); + app.stop(); + + Thread.sleep(2000); + System.out.println("Creating offscreen buffer application"); + app = new LegacyApplication(); + app.start(Type.OffscreenSurface); + Thread.sleep(3000); + System.out.println("Destroying offscreen buffer"); + app.stop(); + } + +} diff --git a/JmeTests/src/jme3test/app/TestBareBonesApp.java b/JmeTests/src/jme3test/app/TestBareBonesApp.java new file mode 100644 index 0000000..491f481 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestBareBonesApp.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.app.LegacyApplication; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** + * Test a bare-bones application, without SimpleApplication. + */ +public class TestBareBonesApp extends LegacyApplication { + + private Geometry boxGeom; + + public static void main(String[] args){ + TestBareBonesApp app = new TestBareBonesApp(); + app.start(); + } + + @Override + public void initialize(){ + super.initialize(); + + System.out.println("Initialize"); + + // create a box + boxGeom = new Geometry("Box", new Box(2, 2, 2)); + + // load some default material + boxGeom.setMaterial(assetManager.loadMaterial("Interface/Logo/Logo.j3m")); + + // attach box to display in primary viewport + viewPort.attachScene(boxGeom); + } + + @Override + public void update(){ + super.update(); + + // do some animation + float tpf = timer.getTimePerFrame(); + boxGeom.rotate(tpf * 2, tpf * 4, tpf * 3); + + // dont forget to update the scenes + boxGeom.updateLogicalState(tpf); + boxGeom.updateGeometricState(); + + // render the viewports + renderManager.render(tpf, context.isRenderable()); + } + + @Override + public void destroy(){ + super.destroy(); + + System.out.println("Destroy"); + } +} diff --git a/JmeTests/src/jme3test/app/TestChangeAppIcon.java b/JmeTests/src/jme3test/app/TestChangeAppIcon.java new file mode 100644 index 0000000..64993c6 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestChangeAppIcon.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.system.AppSettings; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.logging.Logger; +import javax.imageio.ImageIO; + +public class TestChangeAppIcon extends SimpleApplication { + + private static final Logger log=Logger.getLogger(TestChangeAppIcon.class.getName()); + + public static void main(String[] args) { + TestChangeAppIcon app = new TestChangeAppIcon(); + AppSettings settings = new AppSettings(true); + + try { + Class clazz = TestChangeAppIcon.class; + + settings.setIcons(new BufferedImage[]{ + ImageIO.read(clazz.getResourceAsStream("/Interface/icons/SmartMonkey256.png")), + ImageIO.read(clazz.getResourceAsStream("/Interface/icons/SmartMonkey128.png")), + ImageIO.read(clazz.getResourceAsStream("/Interface/icons/SmartMonkey32.png")), + ImageIO.read(clazz.getResourceAsStream("/Interface/icons/SmartMonkey16.png")), + }); + } catch (IOException e) { + log.log(java.util.logging.Level.WARNING, "Unable to load program icons", e); + } + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + // Write text on the screen (HUD) + setDisplayStatView(false); + BitmapText helloText = new BitmapText(guiFont); + helloText.setText("The icon of the app should be a smart monkey!"); + helloText.setLocalTranslation(300, helloText.getLineHeight(), 0); + guiNode.attachChild(helloText); + } +} diff --git a/JmeTests/src/jme3test/app/TestCloneSpatial.java b/JmeTests/src/jme3test/app/TestCloneSpatial.java new file mode 100644 index 0000000..f267f7e --- /dev/null +++ b/JmeTests/src/jme3test/app/TestCloneSpatial.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import java.lang.reflect.*; +import java.util.*; + +import com.jme3.asset.*; +import com.jme3.font.*; +import com.jme3.light.*; +import com.jme3.material.*; +import com.jme3.math.*; +import com.jme3.scene.*; +import com.jme3.scene.control.*; +import com.jme3.scene.shape.*; +import com.jme3.util.clone.*; + + +/** + * + * + * @author Paul Speed + */ +public class TestCloneSpatial { + + public static void main( String... args ) throws Exception { + + // Setup a test node with some children, controls, etc. + Node root = new Node("rootNode"); + + // A root light + DirectionalLight rootLight = new DirectionalLight(); + root.addLight(rootLight); + + Box sharedBox = new Box(1, 1, 1); + Geometry geom1 = new Geometry("box1", sharedBox); + Material sharedMaterial = new Material(); // not a valid material, just for testing + geom1.setMaterial(sharedMaterial); + + Geometry geom2 = new Geometry("box2", sharedBox); + geom2.setMaterial(sharedMaterial); + + root.attachChild(geom1); + root.attachChild(geom2); + + // Add some controls + geom1.addControl(new BillboardControl()); + geom2.addControl(new BillboardControl()); + + // A light that will only affect the children and be controlled + // by one child + PointLight childLight = new PointLight(); + geom1.addLight(childLight); + geom2.addLight(childLight); + + geom1.addControl(new LightControl(childLight)); + + // Set some shared user data also + Vector3f sharedUserData = new Vector3f(1, 2, 3); + geom1.setUserData("shared", sharedUserData); + geom2.setUserData("shared", sharedUserData); + + dump("", root); + + System.out.println("-------- cloning spatial --------------"); + Node clone = root.clone(true); + dump("", clone); + + System.out.println("-------- cloning spatial without cloning material --------------"); + clone = root.clone(false); + dump("", clone); + + System.out.println("-------- cloning BitmapText ------------"); + DesktopAssetManager assets = new DesktopAssetManager(true); + BitmapFont font = assets.loadFont("Interface/Fonts/Console.fnt"); + BitmapText text1 = new BitmapText(font); + text1.setText("Testing"); + System.out.println("Original:"); + dump("", text1); + + System.out.println("Clone:"); + clone = text1.clone(); + dump("", clone); + + } + + + /** + * Debug dump to check structure and identity + */ + public static void dump( String indent, Spatial s ) { + if( s instanceof Node ) { + dump(indent, (Node)s); + } else if( s instanceof Geometry ) { + dump(indent, (Geometry)s); + } + } + + public static void dump( String indent, Node n ) { + System.out.println(indent + objectToString(n)); + dumpSpatialProperties(indent + " ", n); + if( !n.getChildren().isEmpty() ) { + System.out.println(indent + " children:"); + for( Spatial s : n.getChildren() ) { + dump(indent + " ", s); + } + } + } + + public static void dump( String indent, Geometry g ) { + System.out.println(indent + objectToString(g)); + //System.out.println(indent + " mesh:" + objectToString(g.getMesh())); + //System.out.println(indent + " material:" + objectToString(g.getMaterial())); + dumpSpatialProperties(indent + " ", g); + } + + public static void dump( String indent, Control ctl ) { + System.out.println(indent + objectToString(ctl)); + if( ctl instanceof AbstractControl ) { + System.out.println(indent + " spatial:" + objectToString(((AbstractControl)ctl).getSpatial())); + } + } + + private static void dumpSpatialProperties( String indent, Spatial s ) { + dumpProperties(indent, s, "children"); + + if( !s.getUserDataKeys().isEmpty() ) { + System.out.println(indent + "userData:"); + for( String key : s.getUserDataKeys() ) { + System.out.println(indent + " " + key + ":" + objectToString(s.getUserData(key))); + } + } + + if( s.getNumControls() > 0 ) { + System.out.println(indent + "controls:"); + for( int i = 0; i < s.getNumControls(); i++ ) { + Control ctl = s.getControl(i); + //dump(indent + " ", ctl); + dumpObject(indent + " ", ctl); + } + } + + LightList lights = s.getLocalLightList(); + if( lights.size() > 0 ) { + System.out.println(indent + "lights:"); + for( Light l : lights ) { + dumpObject(indent + " ", l); + } + } + } + + private static void dumpObject( String indent, Object o ) { + System.out.println(indent + objectToString(o)); + dumpProperties(indent + " ", o); + } + + private static void dumpProperties( String indent, Object o, String... skip ) { + if( o == null ) { + return; + } + Set skipSet = new HashSet<>(Arrays.asList(skip)); + for( Method m : o.getClass().getMethods() ) { + if( m.getParameterTypes().length > 0 ) { + continue; + } + String name = m.getName(); + if( "getClass".equals(name) ) { + continue; + } + if( !name.startsWith("get") ) { + continue; + } + Class type = m.getReturnType(); + if( type.isPrimitive() || type.isEnum() ) { + continue; + } + name = name.substring(3); + if( skipSet.contains(name.toLowerCase()) ) { + continue; + } + try { + Object value = m.invoke(o); + System.out.println(indent + name + ":" + objectToString(value)); + } catch( Exception e ) { + throw new RuntimeException("Error with method:" + m, e); + } + } + } + + private static String objectToString( Object o ) { + if( o == null ) { + return null; + } + String s = o + "@" + System.identityHashCode(o); + s = s.replaceAll("\\r?\\n", ""); + return s; + } +} diff --git a/JmeTests/src/jme3test/app/TestCloner.java b/JmeTests/src/jme3test/app/TestCloner.java new file mode 100644 index 0000000..cdd33c4 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestCloner.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import java.util.*; + +import com.jme3.util.clone.*; + +/** + * + * + * @author Paul Speed + */ +public class TestCloner { + + public static void main( String... args ) { + + System.out.println("Clone test:"); + + Cloner cloner = new Cloner(); + + RegularObject ro = new RegularObject(42); + System.out.println("Regular Object:" + ro); + RegularObject roCloneLegacy = ro.clone(); + System.out.println("Regular Object Clone:" + roCloneLegacy); + RegularObject roClone = cloner.clone(ro); + System.out.println("cloner: Regular Object Clone:" + roClone); + + System.out.println("------------------------------------"); + System.out.println(); + + cloner = new Cloner(); + RegularSubclass rsc = new RegularSubclass(69, "test"); + System.out.println("Regular subclass:" + rsc); + RegularSubclass rscCloneLegacy = (RegularSubclass)rsc.clone(); + System.out.println("Regular subclass Clone:" + rscCloneLegacy); + RegularSubclass rscClone = cloner.clone(rsc); + System.out.println("cloner: Regular subclass Clone:" + rscClone); + + System.out.println("------------------------------------"); + System.out.println(); + + cloner = new Cloner(); + Parent parent = new Parent("Foo", 34); + System.out.println("Parent:" + parent); + Parent parentCloneLegacy = parent.clone(); + System.out.println("Parent Clone:" + parentCloneLegacy); + Parent parentClone = cloner.clone(parent); + System.out.println("cloner: Parent Clone:" + parentClone); + + System.out.println("------------------------------------"); + System.out.println(); + + cloner = new Cloner(); + GraphNode root = new GraphNode("root"); + GraphNode child1 = root.addLink("child1"); + GraphNode child2 = root.addLink("child2"); + GraphNode shared = child1.addLink("shared"); + child2.addLink(shared); + + // Add a circular reference to get fancy + shared.addLink(root); + + System.out.println("Simple graph:"); + root.dump(" "); + + GraphNode rootClone = cloner.clone(root); + System.out.println("clone:"); + rootClone.dump(" "); + + System.out.println("original:"); + root.dump(" "); + + GraphNode reclone = Cloner.deepClone(root); + System.out.println("reclone:"); + reclone.dump(" "); + + System.out.println("------------------------------------"); + System.out.println(); + cloner = new Cloner(); + + ArrayHolder arrays = new ArrayHolder(5, 3, 7, 3, 7, 2, 1, 4); + System.out.println("Array holder:" + arrays); + ArrayHolder arraysClone = cloner.clone(arrays); + System.out.println("Array holder clone:" + arraysClone); + + + + } + + public static class RegularObject implements Cloneable { + protected int i; + + public RegularObject( int i ) { + this.i = i; + } + + public RegularObject clone() { + try { + return (RegularObject)super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException(e); + } + } + + public String toString() { + return getClass().getSimpleName() + "@" + System.identityHashCode(this) + + "[i=" + i + "]"; + } + } + + public static class RegularSubclass extends RegularObject { + protected String name; + + public RegularSubclass( int i, String name ) { + super(i); + this.name = name; + } + + public String toString() { + return getClass().getSimpleName() + "@" + System.identityHashCode(this) + + "[i=" + i + ", name=" + name + "]"; + } + } + + public static class Parent implements Cloneable, JmeCloneable { + + private RegularObject ro; + private RegularSubclass rsc; + + public Parent( String name, int age ) { + this.ro = new RegularObject(age); + this.rsc = new RegularSubclass(age, name); + } + + public Parent clone() { + try { + return (Parent)super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException(e); + } + } + + public Parent jmeClone() { + // Ok to delegate to clone() in this case because no deep + // cloning is done there. + return clone(); + } + + public void cloneFields( Cloner cloner, Object original ) { + this.ro = cloner.clone(ro); + this.rsc = cloner.clone(rsc); + } + + public String toString() { + return getClass().getSimpleName() + "@" + System.identityHashCode(this) + + "[ro=" + ro + ", rsc=" + rsc + "]"; + } + } + + public static class GraphNode implements Cloneable, JmeCloneable { + + private String name; + private List links = new ArrayList<>(); + + public GraphNode( String name ) { + this.name = name; + } + + public void dump( String indent ) { + dump(indent, new HashSet()); + } + + private void dump( String indent, Set visited ) { + if( visited.contains(this) ) { + // already been here + System.out.println(indent + this + " ** circular."); + return; + } + System.out.println(indent + this); + visited.add(this); + for( GraphNode n : links ) { + n.dump(indent + " ", visited); + } + visited.remove(this); + } + + public GraphNode addLink( String name ) { + GraphNode node = new GraphNode(name); + links.add(node); + return node; + } + + public GraphNode addLink( GraphNode node ) { + links.add(node); + return node; + } + + public List getLinks() { + return links; + } + + public GraphNode jmeClone() { + try { + return (GraphNode)super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException(e); + } + } + + public void cloneFields( Cloner cloner, Object original ) { + this.links = cloner.clone(links); + } + + public String toString() { + return getClass().getSimpleName() + "@" + System.identityHashCode(this) + + "[name=" + name + "]"; + } + } + + public static class ArrayHolder implements JmeCloneable { + + private int[] intArray; + private int[][] intArray2D; + private Object[] objects; + private RegularObject[] regularObjects; + private String[] strings; + + public ArrayHolder( int... values ) { + this.intArray = values; + this.intArray2D = new int[values.length][2]; + for( int i = 0; i < values.length; i++ ) { + intArray2D[i][0] = values[i] + 1; + intArray2D[i][1] = values[i] * 2; + } + this.objects = new Object[values.length]; + this.regularObjects = new RegularObject[values.length]; + this.strings = new String[values.length]; + for( int i = 0; i < values.length; i++ ) { + objects[i] = values[i]; + regularObjects[i] = new RegularObject(values[i]); + strings[i] = String.valueOf(values[i]); + } + } + + public ArrayHolder jmeClone() { + try { + return (ArrayHolder)super.clone(); + } catch( CloneNotSupportedException e ) { + throw new RuntimeException(e); + } + } + + public void cloneFields( Cloner cloner, Object original ) { + intArray = cloner.clone(intArray); + intArray2D = cloner.clone(intArray2D); + + // Boxed types are not cloneable so this will fail + //objects = cloner.clone(objects); + + regularObjects = cloner.clone(regularObjects); + + // Strings are also not cloneable + //strings = cloner.clone(strings); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("intArray=" + intArray); + for( int i = 0; i < intArray.length; i++ ) { + if( i == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append(intArray[i]); + } + sb.append("], "); + + sb.append("intArray2D=" + intArray2D); + for( int i = 0; i < intArray2D.length; i++ ) { + if( i == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append("intArray2D[" + i + "]=" + intArray2D[i]); + for( int j = 0; j < 2; j++ ) { + if( j == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append(intArray2D[i][j]); + } + sb.append("], "); + } + sb.append("], "); + + sb.append("objectArray=" + objects); + for( int i = 0; i < objects.length; i++ ) { + if( i == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append(objects[i]); + } + sb.append("], "); + + sb.append("objectArray=" + regularObjects); + for( int i = 0; i < regularObjects.length; i++ ) { + if( i == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append(regularObjects[i]); + } + sb.append("], "); + + sb.append("stringArray=" + strings); + for( int i = 0; i < strings.length; i++ ) { + if( i == 0 ) { + sb.append("["); + } else { + sb.append(", "); + } + sb.append(strings[i]); + } + sb.append("]"); + + return getClass().getSimpleName() + "@" + System.identityHashCode(this) + + "[" + sb + "]"; + } + } +} diff --git a/JmeTests/src/jme3test/app/TestContextRestart.java b/JmeTests/src/jme3test/app/TestContextRestart.java new file mode 100644 index 0000000..0baaef3 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestContextRestart.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.app.LegacyApplication; +import com.jme3.system.AppSettings; + +public class TestContextRestart { + + public static void main(String[] args) throws InterruptedException{ + AppSettings settings = new AppSettings(true); + + final LegacyApplication app = new LegacyApplication(); + app.setSettings(settings); + app.start(); + + Thread.sleep(3000); + + settings.setFullscreen(true); + settings.setResolution(-1, -1); + app.setSettings(settings); + app.restart(); + + Thread.sleep(3000); + + app.stop(); + } + +} diff --git a/JmeTests/src/jme3test/app/TestCustomAppSettings.java b/JmeTests/src/jme3test/app/TestCustomAppSettings.java new file mode 100644 index 0000000..6a639e9 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestCustomAppSettings.java @@ -0,0 +1,88 @@ +package jme3test.app; + +import com.jme3.scene.Mesh; +import com.jme3.system.AppSettings; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.prefs.BackingStoreException; + +public class TestCustomAppSettings { + + private static final String APPSETTINGS_KEY = "JME_AppSettingsTest"; + + private static void assertEqual(Object a, Object b) { + if (!a.equals(b)){ + throw new AssertionError(); + } + } + + /** + * Tests preference based AppSettings. + */ + private static void testPreferenceSettings() { + AppSettings settings = new AppSettings(false); + settings.putBoolean("TestBool", true); + settings.putInteger("TestInt", 123); + settings.putString("TestStr", "HelloWorld"); + settings.putFloat("TestFloat", 123.567f); + settings.put("TestObj", new Mesh()); // Objects not supported by preferences + + try { + settings.save(APPSETTINGS_KEY); + } catch (BackingStoreException ex) { + ex.printStackTrace(); + } + + AppSettings loadedSettings = new AppSettings(false); + try { + loadedSettings.load(APPSETTINGS_KEY); + } catch (BackingStoreException ex) { + ex.printStackTrace(); + } + + assertEqual(loadedSettings.getBoolean("TestBool"), true); + assertEqual(loadedSettings.getInteger("TestInt"), 123); + assertEqual(loadedSettings.getString("TestStr"), "HelloWorld"); + assertEqual(loadedSettings.get("TestFloat"), 123.567f); + } + + /** + * Test Java properties file based AppSettings. + */ + private static void testFileSettings() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + AppSettings settings = new AppSettings(false); + settings.putBoolean("TestBool", true); + settings.putInteger("TestInt", 123); + settings.putString("TestStr", "HelloWorld"); + settings.putFloat("TestFloat", 123.567f); + settings.put("TestObj", new Mesh()); // Objects not supported by file settings + + try { + settings.save(baos); + } catch (IOException ex) { + ex.printStackTrace(); + } + + AppSettings loadedSettings = new AppSettings(false); + try { + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + loadedSettings.load(bais); + } catch (IOException ex) { + ex.printStackTrace(); + } + + assertEqual(loadedSettings.getBoolean("TestBool"), true); + assertEqual(loadedSettings.getInteger("TestInt"), 123); + assertEqual(loadedSettings.getString("TestStr"), "HelloWorld"); + assertEqual(loadedSettings.get("TestFloat"), 123.567f); + } + + public static void main(String[] args){ + testPreferenceSettings(); + testFileSettings(); + System.out.println("All OK"); + } +} diff --git a/JmeTests/src/jme3test/app/TestEnqueueRunnable.java b/JmeTests/src/jme3test/app/TestEnqueueRunnable.java new file mode 100644 index 0000000..88ce277 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestEnqueueRunnable.java @@ -0,0 +1,72 @@ +package jme3test.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** + * @author john01dav + */ +public class TestEnqueueRunnable extends SimpleApplication{ + private ExampleAsyncTask exampleAsyncTask; + + public static void main(String[] args){ + new TestEnqueueRunnable().start(); + } + + @Override + public void simpleInitApp(){ + Geometry geom = new Geometry("Box", new Box(1, 1, 1)); + Material material = new Material(getAssetManager(), "/Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor("Color", ColorRGBA.Blue); //a color is needed to start with + geom.setMaterial(material); + getRootNode().attachChild(geom); + + exampleAsyncTask = new ExampleAsyncTask(material); + exampleAsyncTask.getThread().start(); + } + + @Override + public void destroy(){ + exampleAsyncTask.endTask(); + super.destroy(); + } + + private class ExampleAsyncTask implements Runnable{ + private final Thread thread; + private final Material material; + private volatile boolean running = true; + + public ExampleAsyncTask(Material material){ + this.thread = new Thread(this); + this.material = material; + } + + public Thread getThread(){ + return thread; + } + + public void run(){ + while(running){ + enqueue(new Runnable(){ //primary usage of this in real applications would use lambda expressions which are unavailable at java 6 + public void run(){ + material.setColor("Color", ColorRGBA.randomColor()); + } + }); + + try{ + Thread.sleep(1000); + }catch(InterruptedException e){} + } + } + + public void endTask(){ + running = false; + thread.interrupt(); + } + + } + +} diff --git a/JmeTests/src/jme3test/app/TestIDList.java b/JmeTests/src/jme3test/app/TestIDList.java new file mode 100644 index 0000000..37f3f56 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestIDList.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.renderer.IDList; +import java.util.*; + +public class TestIDList { + + static class StateCol { + + static Random rand = new Random(); + + Map objs = new HashMap(); + + public StateCol(){ + // populate with free ids + List freeIds = new ArrayList(); + for (int i = 0; i < 16; i++){ + freeIds.add(i); + } + + // create random + int numStates = rand.nextInt(6) + 1; + for (int i = 0; i < numStates; i++){ + // remove a random id from free id list + int idx = rand.nextInt(freeIds.size()); + int id = freeIds.remove(idx); + + objs.put(id, new Object()); + } + } + + public void print(){ + System.out.println("-----------------"); + + Set keys = objs.keySet(); + Integer[] keysArr = keys.toArray(new Integer[0]); + Arrays.sort(keysArr); + for (int i = 0; i < keysArr.length; i++){ + System.out.println(keysArr[i]+" => "+objs.get(keysArr[i]).hashCode()); + } + } + + } + + static IDList list = new IDList(); + static int boundSlot = 0; + + static Object[] slots = new Object[16]; + static boolean[] enabledSlots = new boolean[16]; + + static void enable(int slot){ + System.out.println("Enabled SLOT["+slot+"]"); + if (enabledSlots[slot] == true){ + System.err.println("FAIL! Extra state change"); + } + enabledSlots[slot] = true; + } + + static void disable(int slot){ + System.out.println("Disabled SLOT["+slot+"]"); + if (enabledSlots[slot] == false){ + System.err.println("FAIL! Extra state change"); + } + enabledSlots[slot] = false; + } + + static void setSlot(int slot, Object val){ + if (!list.moveToNew(slot)){ + enable(slot); + } + if (slots[slot] != val){ + System.out.println("SLOT["+slot+"] = "+val.hashCode()); + slots[slot] = val; + } + } + + static void checkSlots(StateCol state){ + for (int i = 0; i < 16; i++){ + if (slots[i] != null && enabledSlots[i] == false){ + System.err.println("FAIL! SLOT["+i+"] assigned, but disabled"); + } + if (slots[i] == null && enabledSlots[i] == true){ + System.err.println("FAIL! SLOT["+i+"] enabled, but not assigned"); + } + + Object val = state.objs.get(i); + if (val != null){ + if (slots[i] != val) + System.err.println("FAIL! SLOT["+i+"] does not contain correct value"); + if (!enabledSlots[i]) + System.err.println("FAIL! SLOT["+i+"] is not enabled"); + }else{ + if (slots[i] != null) + System.err.println("FAIL! SLOT["+i+"] is not set"); + if (enabledSlots[i]) + System.err.println("FAIL! SLOT["+i+"] is enabled"); + } + } + } + + static void clearSlots(){ + for (int i = 0; i < list.oldLen; i++){ + int slot = list.oldList[i]; + disable(slot); + slots[slot] = null; + } + list.copyNewToOld(); +// context.attribIndexList.print(); + } + + static void setState(StateCol state){ + state.print(); + for (Map.Entry entry : state.objs.entrySet()){ + setSlot(entry.getKey(), entry.getValue()); + } + clearSlots(); + checkSlots(state); + } + + public static void main(String[] args){ + StateCol[] states = new StateCol[20]; + for (int i = 0; i < states.length; i++) + states[i] = new StateCol(); + + // shuffle would be useful here.. + + for (int i = 0; i < states.length; i++){ + setState(states[i]); + } + } + +} diff --git a/JmeTests/src/jme3test/app/TestReleaseDirectMemory.java b/JmeTests/src/jme3test/app/TestReleaseDirectMemory.java new file mode 100644 index 0000000..28947c4 --- /dev/null +++ b/JmeTests/src/jme3test/app/TestReleaseDirectMemory.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +public class TestReleaseDirectMemory extends SimpleApplication { + + public static void main(String[] args){ + TestReleaseDirectMemory app = new TestReleaseDirectMemory(); + app.start(); + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + @Override + public void simpleUpdate(float tpf) { + ByteBuffer buf = BufferUtils.createByteBuffer(500000); + BufferUtils.destroyDirectBuffer(buf); + + FloatBuffer buf2 = BufferUtils.createFloatBuffer(500000); + BufferUtils.destroyDirectBuffer(buf2); + } + +} diff --git a/JmeTests/src/jme3test/app/TestResizableApp.java b/JmeTests/src/jme3test/app/TestResizableApp.java new file mode 100644 index 0000000..ad493ab --- /dev/null +++ b/JmeTests/src/jme3test/app/TestResizableApp.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.font.Rectangle; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import jme3test.model.shape.TestBox; + +/** + * Tests the capability to resize the application window. + * + * @author Kirill Vainer + */ +public class TestResizableApp extends SimpleApplication { + + private BitmapText txt; + + public static void main(String[] args){ + TestResizableApp app = new TestResizableApp(); + AppSettings settings = new AppSettings(true); + settings.setResizable(true); + app.setSettings(settings); + app.setShowSettings(false); + app.start(); + } + + public void reshape(int width, int height) { + super.reshape(width, height); + + // Need to move text relative to app height + txt.setLocalTranslation(0, settings.getHeight(), 0); + txt.setText("Drag the corners of the application to resize it.\n" + + "Current Size: " + settings.getWidth() + "x" + settings.getHeight()); + } + + public void simpleInitApp() { + flyCam.setDragToRotate(true); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + txt = new BitmapText(loadGuiFont(), false); + txt.setText("Drag the corners of the application to resize it.\n" + + "Current Size: " + settings.getWidth() + "x" + settings.getHeight()); + txt.setLocalTranslation(0, settings.getHeight(), 0); + guiNode.attachChild(txt); + } + +} diff --git a/JmeTests/src/jme3test/app/TestTempVars.java b/JmeTests/src/jme3test/app/TestTempVars.java new file mode 100644 index 0000000..7700b2e --- /dev/null +++ b/JmeTests/src/jme3test/app/TestTempVars.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.app; + +import com.jme3.math.Vector3f; +import com.jme3.util.TempVars; + +public class TestTempVars { + + private static final int ITERATIONS = 10000000; + private static final int NANOS_TO_MS = 1000000; + + private static final Vector3f sumCompute = new Vector3f(); + + public static void main(String[] args) { + long milliseconds, nanos; + + for (int i = 0; i < 4; i++){ + System.gc(); + } + +// sumCompute.set(0, 0, 0); +// long nanos = System.nanoTime(); +// for (int i = 0; i < ITERATIONS; i++) { +// recursiveMethod(0); +// } +// long milliseconds = (System.nanoTime() - nanos) / NANOS_TO_MS; +// System.out.println("100 million TempVars calls with 5 recursions: " + milliseconds + " ms"); +// System.out.println(sumCompute); + + sumCompute.set(0, 0, 0); + nanos = System.nanoTime(); + for (int i = 0; i < ITERATIONS; i++) { + methodThatUsesTempVars(); + } + milliseconds = (System.nanoTime() - nanos) / NANOS_TO_MS; + System.out.println("100 million TempVars calls: " + milliseconds + " ms"); + System.out.println(sumCompute); + + sumCompute.set(0, 0, 0); + nanos = System.nanoTime(); + for (int i = 0; i < ITERATIONS; i++) { + methodThatUsesAllocation(); + } + milliseconds = (System.nanoTime() - nanos) / NANOS_TO_MS; + System.out.println("100 million allocation calls: " + milliseconds + " ms"); + System.out.println(sumCompute); + + nanos = System.nanoTime(); + for (int i = 0; i < 10; i++){ + System.gc(); + } + milliseconds = (System.nanoTime() - nanos) / NANOS_TO_MS; + System.out.println("cleanup time after allocation calls: " + milliseconds + " ms"); + } + + public static void methodThatUsesAllocation(){ + Vector3f vector = new Vector3f(); + vector.set(0.1f, 0.2f, 0.3f); + sumCompute.addLocal(vector); + } + + public static void recursiveMethod(int recurse) { + TempVars vars = TempVars.get(); + { + vars.vect1.set(0.1f, 0.2f, 0.3f); + + if (recurse < 4) { + recursiveMethod(recurse + 1); + } + + sumCompute.addLocal(vars.vect1); + } + vars.release(); + } + + public static void methodThatUsesTempVars() { + TempVars vars = TempVars.get(); + { + vars.vect1.set(0.1f, 0.2f, 0.3f); + sumCompute.addLocal(vars.vect1); + } + vars.release(); + } +} diff --git a/JmeTests/src/jme3test/app/TestUseAfterFree.java b/JmeTests/src/jme3test/app/TestUseAfterFree.java new file mode 100644 index 0000000..ee52d0f --- /dev/null +++ b/JmeTests/src/jme3test/app/TestUseAfterFree.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.texture.Texture; +import com.jme3.util.BufferUtils; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestUseAfterFree extends SimpleApplication { + + private float time = 0; + private Material mat; + private Texture deletedTex; + + public static void main(String[] args) { + TestUseAfterFree app = new TestUseAfterFree(); + app.start(); + } + + @Override + public void simpleInitApp() { + Box box = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", box); + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + @Override + public void simpleUpdate(float tpf) { + if (time < 0) { + if (deletedTex != null) { + deletedTex.getImage().resetObject(); + } + return; + } + + time += tpf; + if (time > 5) { + System.out.println("Assiging texture to deleted object!"); + + deletedTex = assetManager.loadTexture("Interface/Logo/Monkey.png"); + BufferUtils.destroyDirectBuffer(deletedTex.getImage().getData(0)); + mat.setTexture("ColorMap", deletedTex); + + time = -1; + } + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/app/state/RootNodeState.java b/JmeTests/src/jme3test/app/state/RootNodeState.java new file mode 100644 index 0000000..9274f99 --- /dev/null +++ b/JmeTests/src/jme3test/app/state/RootNodeState.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app.state; + +import com.jme3.app.state.AbstractAppState; +import com.jme3.scene.Node; + +public class RootNodeState extends AbstractAppState { + + private Node rootNode = new Node("Root Node"); + + public Node getRootNode(){ + return rootNode; + } + + @Override + public void update(float tpf) { + super.update(tpf); + + rootNode.updateLogicalState(tpf); + rootNode.updateGeometricState(); + } + +} diff --git a/JmeTests/src/jme3test/app/state/TestAppStates.java b/JmeTests/src/jme3test/app/state/TestAppStates.java new file mode 100644 index 0000000..a19e2ad --- /dev/null +++ b/JmeTests/src/jme3test/app/state/TestAppStates.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.app.state; + +import com.jme3.app.LegacyApplication; +import com.jme3.niftygui.NiftyJmeDisplay; +import com.jme3.scene.Spatial; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext; + +public class TestAppStates extends LegacyApplication { + + public static void main(String[] args){ + TestAppStates app = new TestAppStates(); + app.start(); + } + + @Override + public void start(JmeContext.Type contextType){ + AppSettings settings = new AppSettings(true); + settings.setResolution(1024, 768); + setSettings(settings); + + super.start(contextType); + } + + @Override + public void initialize(){ + super.initialize(); + + System.out.println("Initialize"); + + RootNodeState state = new RootNodeState(); + viewPort.attachScene(state.getRootNode()); + stateManager.attach(state); + + Spatial model = assetManager.loadModel("Models/Teapot/Teapot.obj"); + model.scale(3); + model.setMaterial(assetManager.loadMaterial("Interface/Logo/Logo.j3m")); + state.getRootNode().attachChild(model); + + NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, + inputManager, + audioRenderer, + guiViewPort); + niftyDisplay.getNifty().fromXml("Interface/Nifty/HelloJme.xml", "start"); + guiViewPort.addProcessor(niftyDisplay); + } + + @Override + public void update(){ + super.update(); + + // do some animation + float tpf = timer.getTimePerFrame(); + + stateManager.update(tpf); + stateManager.render(renderManager); + + // render the viewports + renderManager.render(tpf, context.isRenderable()); + } + + @Override + public void destroy(){ + super.destroy(); + + System.out.println("Destroy"); + } +} diff --git a/JmeTests/src/jme3test/asset/TestAbsoluteLocators.java b/JmeTests/src/jme3test/asset/TestAbsoluteLocators.java new file mode 100644 index 0000000..be67acb --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestAbsoluteLocators.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.asset.AssetManager; +import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.audio.AudioData; +import com.jme3.audio.plugins.WAVLoader; +import com.jme3.system.JmeSystem; +import com.jme3.texture.Texture; +import com.jme3.texture.plugins.AWTLoader; + +public class TestAbsoluteLocators { + public static void main(String[] args){ + AssetManager am = JmeSystem.newAssetManager(); + + am.registerLoader(AWTLoader.class, "jpg"); + am.registerLoader(WAVLoader.class, "wav"); + + // register absolute locator + am.registerLocator("/", ClasspathLocator.class); + + // find a sound + AudioData audio = am.loadAudio("Sound/Effects/Gun.wav"); + + // find a texture + Texture tex = am.loadTexture("Textures/Terrain/Pond/Pond.jpg"); + + if (audio == null) + throw new RuntimeException("Cannot find audio!"); + else + System.out.println("Audio loaded from Sounds/Effects/Gun.wav"); + + if (tex == null) + throw new RuntimeException("Cannot find texture!"); + else + System.out.println("Texture loaded from Textures/Terrain/Pond/Pond.jpg"); + + System.out.println("Success!"); + } +} diff --git a/JmeTests/src/jme3test/asset/TestAssetCache.java b/JmeTests/src/jme3test/asset/TestAssetCache.java new file mode 100644 index 0000000..2f86e9a --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestAssetCache.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetProcessor; +import com.jme3.asset.CloneableAssetProcessor; +import com.jme3.asset.CloneableSmartAsset; +import com.jme3.asset.cache.AssetCache; +import com.jme3.asset.cache.SimpleAssetCache; +import com.jme3.asset.cache.WeakRefAssetCache; +import com.jme3.asset.cache.WeakRefCloneAssetCache; +import java.util.ArrayList; +import java.util.List; + +public class TestAssetCache { + + /** + * Counter for asset keys + */ + private static int counter = 0; + + /** + * Dummy data is an asset having 10 KB to put a dent in the garbage collector + */ + private static class DummyData implements CloneableSmartAsset { + + private AssetKey key; + private byte[] data = new byte[10 * 1024]; + + @Override + public Object clone(){ + try { + DummyData clone = (DummyData) super.clone(); + clone.data = data.clone(); + return clone; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(); + } + } + + public byte[] getData(){ + return data; + } + + public AssetKey getKey() { + return key; + } + + public void setKey(AssetKey key) { + this.key = key; + } + } + + /** + * Dummy key is indexed by a generated ID + */ + private static class DummyKey extends AssetKey implements Cloneable { + + private int id = 0; + + public DummyKey(){ + super("."); + id = counter++; + } + + public DummyKey(int id){ + super("."); + this.id = id; + } + + @Override + public int hashCode(){ + return id; + } + + @Override + public boolean equals(Object other){ + return ((DummyKey)other).id == id; + } + + @Override + public DummyKey clone(){ + return new DummyKey(id); + } + + @Override + public String toString() { + return "ID=" + id; + } + } + + private static void runTest(boolean cloneAssets, boolean smartCache, boolean keepRefs, int limit) { + counter = 0; + List refs = new ArrayList(limit); + + AssetCache cache; + AssetProcessor proc = null; + + if (cloneAssets) { + proc = new CloneableAssetProcessor(); + } + + if (smartCache) { + if (cloneAssets) { + cache = new WeakRefCloneAssetCache(); + } else { + cache = new WeakRefAssetCache(); + } + } else { + cache = new SimpleAssetCache(); + } + + System.gc(); + System.gc(); + System.gc(); + System.gc(); + + long memory = Runtime.getRuntime().freeMemory(); + + while (counter < limit){ + // Create a key + DummyKey key = new DummyKey(); + + // Create some data + DummyData data = new DummyData(); + + // Post process the data before placing it in the cache + if (proc != null){ + data = (DummyData) proc.postProcess(key, data); + } + + if (data.key != null){ + // Keeping a hard reference to the key in the cache + // means the asset will never be collected => bug + throw new AssertionError(); + } + + cache.addToCache(key, data); + + // Get the asset from the cache + AssetKey keyToGet = key.clone(); + + // NOTE: Commented out because getFromCache leaks the original key +// DummyData someLoaded = (DummyData) cache.getFromCache(keyToGet); +// if (someLoaded != data){ +// // Failed to get the same asset from the cache => bug +// // Since a hard reference to the key is kept, +// // it cannot be collected at this point. +// throw new AssertionError(); +// } + + // Clone the asset + if (proc != null){ + // Data is now the clone! + data = (DummyData) proc.createClone(data); + if (smartCache) { + // Registering a clone is only needed + // if smart cache is used. + cache.registerAssetClone(keyToGet, data); + // The clone of the asset must have the same key as the original + // otherwise => bug + if (data.key != key){ + throw new AssertionError(); + } + } + } + + // Keep references to the asset => *should* prevent + // collections of the asset in the cache thus causing + // an out of memory error. + if (keepRefs){ + // Prevent the saved references from taking too much memory .. + if (cloneAssets) { + data.data = null; + } + refs.add(data); + } + + if ((counter % 1000) == 0){ + long newMem = Runtime.getRuntime().freeMemory(); + System.out.println("Allocated objects: " + counter); + System.out.println("Allocated memory: " + ((memory - newMem)/(1024*1024)) + " MB" ); + memory = newMem; + } + } + } + + public static void main(String[] args){ + // Test cloneable smart asset + System.out.println("====== Running Cloneable Smart Asset Test ======"); + runTest(true, true, false, 100000); + + // Test non-cloneable smart asset + System.out.println("====== Running Non-cloneable Smart Asset Test ======"); + runTest(false, true, false, 100000); + } +} diff --git a/JmeTests/src/jme3test/asset/TestCustomLoader.java b/JmeTests/src/jme3test/asset/TestCustomLoader.java new file mode 100644 index 0000000..cb9e851 --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestCustomLoader.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.asset.AssetLoader; +import com.jme3.asset.AssetManager; +import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.system.JmeSystem; + +/** + * Demonstrates loading a file from a custom {@link AssetLoader} + */ +public class TestCustomLoader { + public static void main(String[] args){ + AssetManager assetManager = JmeSystem.newAssetManager(); + assetManager.registerLocator("/", ClasspathLocator.class); + assetManager.registerLoader(TextLoader.class, "fnt"); + System.out.println(assetManager.loadAsset("Interface/Fonts/Console.fnt")); + } +} diff --git a/JmeTests/src/jme3test/asset/TestManyLocators.java b/JmeTests/src/jme3test/asset/TestManyLocators.java new file mode 100644 index 0000000..b7b5205 --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestManyLocators.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.asset.*; +import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.UrlLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.system.JmeSystem; + +public class TestManyLocators { + public static void main(String[] args){ + AssetManager am = JmeSystem.newAssetManager(); + + am.registerLocator("http://www.jmonkeyengine.com/wp-content/uploads/2010/09/", + UrlLocator.class); + + am.registerLocator("town.zip", ZipLocator.class); + am.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip", + HttpZipLocator.class); + + + am.registerLocator("/", ClasspathLocator.class); + + + + // Try loading from Core-Data source package + AssetInfo a = am.locateAsset(new AssetKey("Interface/Fonts/Default.fnt")); + + // Try loading from town scene zip file + AssetInfo b = am.locateAsset(new ModelKey("casaamarela.jpg")); + + // Try loading from wildhouse online scene zip file + AssetInfo c = am.locateAsset(new ModelKey("glasstile2.png")); + + // Try loading directly from HTTP + AssetInfo d = am.locateAsset(new TextureKey("planet-2.jpg")); + + if (a == null) + System.out.println("Failed to load from classpath"); + else + System.out.println("Found classpath font: " + a.toString()); + + if (b == null) + System.out.println("Failed to load from town.zip"); + else + System.out.println("Found zip image: " + b.toString()); + + if (c == null) + System.out.println("Failed to load from wildhouse.zip on googlecode.com"); + else + System.out.println("Found online zip image: " + c.toString()); + + if (d == null) + System.out.println("Failed to load from HTTP"); + else + System.out.println("Found HTTP showcase image: " + d.toString()); + } +} diff --git a/JmeTests/src/jme3test/asset/TestOnlineJar.java b/JmeTests/src/jme3test/asset/TestOnlineJar.java new file mode 100644 index 0000000..1de154f --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestOnlineJar.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Texture; +import com.jme3.ui.Picture; + +/** + * This tests loading a file from a jar stored online. + * @author Kirill Vainer + */ +public class TestOnlineJar extends SimpleApplication { + + public static void main(String[] args){ + TestOnlineJar app = new TestOnlineJar(); + app.start(); + } + + @Override + public void simpleInitApp() { + // create a simple plane/quad + Quad quadMesh = new Quad(1, 1); + quadMesh.updateGeometry(1, 1, true); + + Geometry quad = new Geometry("Textured Quad", quadMesh); + + assetManager.registerLocator("https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/town.zip", + HttpZipLocator.class); + assetManager.registerLocator("https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/wildhouse.zip", + HttpZipLocator.class); + + Picture pic1 = new Picture("Picture1"); + pic1.move(0, 0, -1); + pic1.setPosition(0, 0); + pic1.setWidth(128); + pic1.setHeight(128); + pic1.setImage(assetManager, "grass.jpg", false); + guiNode.attachChild(pic1); + + Picture pic2 = new Picture("Picture1"); + pic2.move(0, 0, -1); + pic2.setPosition(128, 0); + pic2.setWidth(128); + pic2.setHeight(128); + pic2.setImage(assetManager, "glasstile2.png", false); + guiNode.attachChild(pic2); + } + +} diff --git a/JmeTests/src/jme3test/asset/TestUrlLoading.java b/JmeTests/src/jme3test/asset/TestUrlLoading.java new file mode 100644 index 0000000..563eb4c --- /dev/null +++ b/JmeTests/src/jme3test/asset/TestUrlLoading.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.asset; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.asset.plugins.UrlLocator; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Texture; + +/** + * Load an image and display it from the internet using the UrlLocator. + * @author Kirill Vainer + */ +public class TestUrlLoading extends SimpleApplication { + + public static void main(String[] args){ + TestUrlLoading app = new TestUrlLoading(); + app.start(); + } + + @Override + public void simpleInitApp() { + // create a simple plane/quad + Quad quadMesh = new Quad(1, 1); + quadMesh.updateGeometry(1, 1, true); + + Geometry quad = new Geometry("Textured Quad", quadMesh); + + assetManager.registerLocator("https://raw.githubusercontent.com/jMonkeyEngine/BookSamples/master/assets/Textures/", + UrlLocator.class); + TextureKey key = new TextureKey("mucha-window.png", false); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", tex); + quad.setMaterial(mat); + + float aspect = tex.getImage().getWidth() / (float) tex.getImage().getHeight(); + quad.setLocalScale(new Vector3f(aspect * 1.5f, 1.5f, 1)); + quad.center(); + + rootNode.attachChild(quad); + } + +} diff --git a/JmeTests/src/jme3test/asset/TextLoader.java b/JmeTests/src/jme3test/asset/TextLoader.java new file mode 100644 index 0000000..baff118 --- /dev/null +++ b/JmeTests/src/jme3test/asset/TextLoader.java @@ -0,0 +1,25 @@ +package jme3test.asset; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetLoader; +import java.io.IOException; +import java.util.Scanner; + +/** + * An example implementation of {@link AssetLoader} to load text + * files as strings. + */ +public class TextLoader implements AssetLoader { + public Object load(AssetInfo assetInfo) throws IOException { + Scanner scan = new Scanner(assetInfo.openStream()); + StringBuilder sb = new StringBuilder(); + try { + while (scan.hasNextLine()) { + sb.append(scan.nextLine()).append('\n'); + } + } finally { + scan.close(); + } + return sb.toString(); + } +} diff --git a/JmeTests/src/jme3test/audio/TestAmbient.java b/JmeTests/src/jme3test/audio/TestAmbient.java new file mode 100644 index 0000000..6d30052 --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestAmbient.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData.DataType; +import com.jme3.audio.AudioNode; +import com.jme3.audio.Environment; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +public class TestAmbient extends SimpleApplication { + + private AudioNode nature, waves; + + public static void main(String[] args) { + TestAmbient test = new TestAmbient(); + test.start(); + } + + @Override + public void simpleInitApp() { + float[] eax = new float[]{15, 38.0f, 0.300f, -1000, -3300, 0, + 1.49f, 0.54f, 1.00f, -2560, 0.162f, 0.00f, 0.00f, + 0.00f, -229, 0.088f, 0.00f, 0.00f, 0.00f, 0.125f, 1.000f, + 0.250f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.00f, 0x3f}; + Environment env = new Environment(eax); + audioRenderer.setEnvironment(env); + + waves = new AudioNode(assetManager, "Sound/Environment/Ocean Waves.ogg", + DataType.Buffer); + waves.setPositional(true); + waves.setLocalTranslation(new Vector3f(0, 0,0)); + waves.setMaxDistance(100); + waves.setRefDistance(5); + + nature = new AudioNode(assetManager, "Sound/Environment/Nature.ogg", + DataType.Stream); + nature.setPositional(false); + nature.setVolume(3); + + waves.playInstance(); + nature.play(); + + // just a blue box to mark the spot + Box box1 = new Box(.5f, .5f, .5f); + Geometry player = new Geometry("Player", box1); + Material mat1 = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Blue); + player.setMaterial(mat1); + rootNode.attachChild(player); + } + + @Override + public void simpleUpdate(float tpf) { + } +} diff --git a/JmeTests/src/jme3test/audio/TestDoppler.java b/JmeTests/src/jme3test/audio/TestDoppler.java new file mode 100644 index 0000000..1065e1c --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestDoppler.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Torus; + +/** + * Test Doppler Effect + */ +public class TestDoppler extends SimpleApplication { + + private float pos = -5; + private float vel = 5; + private AudioNode ufoNode; + + public static void main(String[] args){ + TestDoppler test = new TestDoppler(); + test.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + + Torus torus = new Torus(10, 6, 1, 3); + Geometry g = new Geometry("Torus Geom", torus); + g.rotate(-FastMath.HALF_PI, 0, 0); + g.center(); + + g.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); +// rootNode.attachChild(g); + + ufoNode = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", AudioData.DataType.Buffer); + ufoNode.setLooping(true); + ufoNode.setPitch(0.5f); + ufoNode.setRefDistance(1); + ufoNode.setMaxDistance(100000000); + ufoNode.setVelocityFromTranslation(true); + ufoNode.play(); + + Geometry ball = new Geometry("Beeper", new Sphere(10, 10, 0.1f)); + ball.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + ufoNode.attachChild(ball); + + rootNode.attachChild(ufoNode); + } + + + @Override + public void simpleUpdate(float tpf) { + pos += tpf * vel; + if (pos < -10 || pos > 10) { + vel *= -1; + } + ufoNode.setLocalTranslation(new Vector3f(pos, 0, 0)); + } +} diff --git a/JmeTests/src/jme3test/audio/TestMusicPlayer.form b/JmeTests/src/jme3test/audio/TestMusicPlayer.form new file mode 100644 index 0000000..2834858 --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestMusicPlayer.form @@ -0,0 +1,117 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JmeTests/src/jme3test/audio/TestMusicPlayer.java b/JmeTests/src/jme3test/audio/TestMusicPlayer.java new file mode 100644 index 0000000..50fe745 --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestMusicPlayer.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.audio; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetLoader; +import com.jme3.audio.*; +import com.jme3.audio.AudioSource.Status; +import com.jme3.audio.plugins.OGGLoader; +import com.jme3.audio.plugins.WAVLoader; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeSystem; +import java.io.*; +import javax.swing.JFileChooser; + +public class TestMusicPlayer extends javax.swing.JFrame { + + private AudioRenderer ar; + private AudioData musicData; + private AudioNode musicSource; + private float musicLength = 0; + private float curTime = 0; + private Listener listener = new Listener(); + + public TestMusicPlayer() { + initComponents(); + setLocationRelativeTo(null); + initAudioPlayer(); + } + + private void initAudioPlayer(){ + AppSettings settings = new AppSettings(true); + settings.setRenderer(null); // disable rendering + settings.setAudioRenderer("LWJGL"); + ar = JmeSystem.newAudioRenderer(settings); + ar.initialize(); + ar.setListener(listener); + AudioContext.setAudioRenderer(ar); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + pnlButtons = new javax.swing.JPanel(); + sldVolume = new javax.swing.JSlider(); + btnRewind = new javax.swing.JButton(); + btnStop = new javax.swing.JButton(); + btnPlay = new javax.swing.JButton(); + btnFF = new javax.swing.JButton(); + btnOpen = new javax.swing.JButton(); + pnlBar = new javax.swing.JPanel(); + lblTime = new javax.swing.JLabel(); + sldBar = new javax.swing.JSlider(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent evt) { + formWindowClosing(evt); + } + }); + + pnlButtons.setLayout(new javax.swing.BoxLayout(pnlButtons, javax.swing.BoxLayout.LINE_AXIS)); + + sldVolume.setMajorTickSpacing(20); + sldVolume.setOrientation(javax.swing.JSlider.VERTICAL); + sldVolume.setPaintTicks(true); + sldVolume.setValue(100); + sldVolume.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + sldVolumeStateChanged(evt); + } + }); + pnlButtons.add(sldVolume); + + btnRewind.setText("<<"); + pnlButtons.add(btnRewind); + + btnStop.setText("[ ]"); + btnStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnStopActionPerformed(evt); + } + }); + pnlButtons.add(btnStop); + + btnPlay.setText("II / >"); + btnPlay.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnPlayActionPerformed(evt); + } + }); + pnlButtons.add(btnPlay); + + btnFF.setText(">>"); + btnFF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFFActionPerformed(evt); + } + }); + pnlButtons.add(btnFF); + + btnOpen.setText("Open ..."); + btnOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOpenActionPerformed(evt); + } + }); + pnlButtons.add(btnOpen); + + getContentPane().add(pnlButtons, java.awt.BorderLayout.CENTER); + + pnlBar.setLayout(new javax.swing.BoxLayout(pnlBar, javax.swing.BoxLayout.LINE_AXIS)); + + lblTime.setText("0:00-0:00"); + lblTime.setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 3, 3, 3)); + pnlBar.add(lblTime); + + sldBar.setValue(0); + sldBar.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + sldBarStateChanged(evt); + } + }); + pnlBar.add(sldBar); + + getContentPane().add(pnlBar, java.awt.BorderLayout.PAGE_START); + + pack(); + }// //GEN-END:initComponents + + private void btnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOpenActionPerformed + JFileChooser chooser = new JFileChooser(); + chooser.setAcceptAllFileFilterUsed(true); + chooser.setDialogTitle("Select OGG file"); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setMultiSelectionEnabled(false); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){ + btnStopActionPerformed(null); + + final File selected = chooser.getSelectedFile(); + AssetLoader loader = null; + if(selected.getName().endsWith(".wav")){ + loader = new WAVLoader(); + }else{ + loader = new OGGLoader(); + } + + AudioKey key = new AudioKey(selected.getName(), true, true); + try{ + musicData = (AudioData) loader.load(new AssetInfo(null, key) { + @Override + public InputStream openStream() { + try{ + return new FileInputStream(selected); + }catch (FileNotFoundException ex){ + ex.printStackTrace(); + } + return null; + } + }); + }catch (IOException ex){ + ex.printStackTrace(); + } + + musicSource = new AudioNode(musicData, key); + musicLength = musicData.getDuration(); + updateTime(); + } + }//GEN-LAST:event_btnOpenActionPerformed + + private void updateTime(){ + int max = (int) (musicLength * 100); + int pos = (int) (curTime * 100); + sldBar.setMaximum(max); + sldBar.setValue(pos); + + int minutesTotal = (int) (musicLength / 60); + int secondsTotal = (int) (musicLength % 60); + int minutesNow = (int) (curTime / 60); + int secondsNow = (int) (curTime % 60); + String txt = String.format("%01d:%02d-%01d:%02d", minutesNow, secondsNow, + minutesTotal, secondsTotal); + lblTime.setText(txt); + } + + private void btnPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPlayActionPerformed + if (musicSource == null){ + btnOpenActionPerformed(evt); + return; + } + + if (musicSource.getStatus() == Status.Playing){ + musicSource.setPitch(1); + ar.pauseSource(musicSource); + }else{ + musicSource.setPitch(1); + musicSource.play(); + } + }//GEN-LAST:event_btnPlayActionPerformed + + private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing + ar.cleanup(); + }//GEN-LAST:event_formWindowClosing + + private void sldVolumeStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sldVolumeStateChanged + listener.setVolume( (float) sldVolume.getValue() / 100f); + ar.setListener(listener); + }//GEN-LAST:event_sldVolumeStateChanged + + private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopActionPerformed + if (musicSource != null){ + musicSource.setPitch(1); + ar.stopSource(musicSource); + } + }//GEN-LAST:event_btnStopActionPerformed + + private void btnFFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFFActionPerformed + if (musicSource.getStatus() == Status.Playing){ + musicSource.setPitch(2); + } + }//GEN-LAST:event_btnFFActionPerformed + + private void sldBarStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sldBarStateChanged + if (musicSource != null && !sldBar.getValueIsAdjusting()){ + curTime = sldBar.getValue() / 100f; + if (curTime < 0) + curTime = 0; + + musicSource.setTimeOffset(curTime); +// if (musicSource.getStatus() == Status.Playing){ +// musicSource.stop(); +// musicSource.play(); +// } + updateTime(); + } + }//GEN-LAST:event_sldBarStateChanged + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new TestMusicPlayer().setVisible(true); + } + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnFF; + private javax.swing.JButton btnOpen; + private javax.swing.JButton btnPlay; + private javax.swing.JButton btnRewind; + private javax.swing.JButton btnStop; + private javax.swing.JLabel lblTime; + private javax.swing.JPanel pnlBar; + private javax.swing.JPanel pnlButtons; + private javax.swing.JSlider sldBar; + private javax.swing.JSlider sldVolume; + // End of variables declaration//GEN-END:variables + +} diff --git a/JmeTests/src/jme3test/audio/TestMusicStreaming.java b/JmeTests/src/jme3test/audio/TestMusicStreaming.java new file mode 100644 index 0000000..35332b1 --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestMusicStreaming.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.UrlLocator; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; + +public class TestMusicStreaming extends SimpleApplication { + + public static void main(String[] args){ + TestMusicStreaming test = new TestMusicStreaming(); + test.start(); + } + + @Override + public void simpleInitApp(){ + assetManager.registerLocator("http://www.vorbis.com/music/", UrlLocator.class); + AudioNode audioSource = new AudioNode(assetManager, "Lumme-Badloop.ogg", + AudioData.DataType.Stream); + audioSource.setPositional(false); + audioSource.setReverbEnabled(false); + audioSource.play(); + } + + @Override + public void simpleUpdate(float tpf){} + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/audio/TestOgg.java b/JmeTests/src/jme3test/audio/TestOgg.java new file mode 100644 index 0000000..3e4099c --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestOgg.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData.DataType; +import com.jme3.audio.AudioNode; +import com.jme3.audio.AudioSource; +import com.jme3.audio.LowPassFilter; + +public class TestOgg extends SimpleApplication { + + private AudioNode audioSource; + + public static void main(String[] args){ + TestOgg test = new TestOgg(); + test.start(); + } + + @Override + public void simpleInitApp(){ + System.out.println("Playing without filter"); + audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer); + audioSource.play(); + } + + @Override + public void simpleUpdate(float tpf){ + if (audioSource.getStatus() != AudioSource.Status.Playing){ + audioRenderer.deleteAudioData(audioSource.getAudioData()); + + System.out.println("Playing with low pass filter"); + audioSource = new AudioNode(assetManager, "Sound/Effects/Foot steps.ogg", DataType.Buffer); + audioSource.setDryFilter(new LowPassFilter(1f, .1f)); + audioSource.setVolume(3); + audioSource.play(); + } + } + +} diff --git a/JmeTests/src/jme3test/audio/TestReverb.java b/JmeTests/src/jme3test/audio/TestReverb.java new file mode 100644 index 0000000..8fd5d1b --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestReverb.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; +import com.jme3.audio.Environment; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; + +public class TestReverb extends SimpleApplication { + + private AudioNode audioSource; + private float time = 0; + private float nextTime = 1; + + public static void main(String[] args) { + TestReverb test = new TestReverb(); + test.start(); + } + + @Override + public void simpleInitApp() { + audioSource = new AudioNode(assetManager, "Sound/Effects/Bang.wav", + AudioData.DataType.Buffer); + + float[] eax = new float[]{15, 38.0f, 0.300f, -1000, -3300, 0, + 1.49f, 0.54f, 1.00f, -2560, 0.162f, 0.00f, 0.00f, 0.00f, + -229, 0.088f, 0.00f, 0.00f, 0.00f, 0.125f, 1.000f, 0.250f, + 0.000f, -5.0f, 5000.0f, 250.0f, 0.00f, 0x3f}; + audioRenderer.setEnvironment(new Environment(eax)); + Environment env = Environment.Cavern; + audioRenderer.setEnvironment(env); + } + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + + if (time > nextTime) { + Vector3f v = new Vector3f(); + v.setX(FastMath.nextRandomFloat()); + v.setY(FastMath.nextRandomFloat()); + v.setZ(FastMath.nextRandomFloat()); + v.multLocal(40, 2, 40); + v.subtractLocal(20, 1, 20); + + audioSource.setLocalTranslation(v); + audioSource.playInstance(); + time = 0; + nextTime = FastMath.nextRandomFloat() * 2 + 0.5f; + } + } +} diff --git a/JmeTests/src/jme3test/audio/TestWav.java b/JmeTests/src/jme3test/audio/TestWav.java new file mode 100644 index 0000000..09fcfe7 --- /dev/null +++ b/JmeTests/src/jme3test/audio/TestWav.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.audio; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; + +public class TestWav extends SimpleApplication { + + private float time = 0; + private AudioNode audioSource; + + public static void main(String[] args) { + TestWav test = new TestWav(); + test.start(); + } + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + if (time > 1f) { + audioSource.playInstance(); + time = 0; + } + + } + + @Override + public void simpleInitApp() { + audioSource = new AudioNode(assetManager, "Sound/Effects/Gun.wav", + AudioData.DataType.Buffer); + audioSource.setLooping(false); + } +} diff --git a/JmeTests/src/jme3test/awt/AppHarness.java b/JmeTests/src/jme3test/awt/AppHarness.java new file mode 100644 index 0000000..77e8d70 --- /dev/null +++ b/JmeTests/src/jme3test/awt/AppHarness.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.awt; + +import com.jme3.app.LegacyApplication; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; +import com.jme3.system.JmeSystem; +import java.applet.Applet; +import java.awt.Canvas; +import java.awt.Graphics; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import javax.swing.SwingUtilities; + +/** + * + * @author Kirill + */ +public class AppHarness extends Applet { + + private JmeCanvasContext context; + private Canvas canvas; + private LegacyApplication app; + + private String appClass; + private URL appCfg = null; + + private void createCanvas(){ + AppSettings settings = new AppSettings(true); + + // load app cfg + if (appCfg != null){ + try { + InputStream in = appCfg.openStream(); + settings.load(in); + in.close(); + } catch (IOException ex){ + ex.printStackTrace(); + } + } + + settings.setWidth(getWidth()); + settings.setHeight(getHeight()); + settings.setAudioRenderer(null); + + JmeSystem.setLowPermissions(true); + + try{ + Class clazz = (Class) Class.forName(appClass); + app = clazz.newInstance(); + }catch (ClassNotFoundException ex){ + ex.printStackTrace(); + }catch (InstantiationException ex){ + ex.printStackTrace(); + }catch (IllegalAccessException ex){ + ex.printStackTrace(); + } + + app.setSettings(settings); + app.createCanvas(); + + context = (JmeCanvasContext) app.getContext(); + canvas = context.getCanvas(); + canvas.setSize(getWidth(), getHeight()); + + add(canvas); + app.startCanvas(); + } + + @Override + public final void update(Graphics g) { + canvas.setSize(getWidth(), getHeight()); + } + + @Override + public void init(){ + appClass = getParameter("AppClass"); + if (appClass == null) + throw new RuntimeException("The required parameter AppClass isn't specified!"); + + try { + appCfg = new URL(getParameter("AppSettingsURL")); + } catch (MalformedURLException ex) { + ex.printStackTrace(); + appCfg = null; + } + + createCanvas(); + System.out.println("applet:init"); + } + + @Override + public void start(){ + context.setAutoFlushFrames(true); + System.out.println("applet:start"); + } + + @Override + public void stop(){ + context.setAutoFlushFrames(false); + System.out.println("applet:stop"); + } + + @Override + public void destroy(){ + System.out.println("applet:destroyStart"); + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + removeAll(); + System.out.println("applet:destroyRemoved"); + } + }); + app.stop(true); + System.out.println("applet:destroyDone"); + } + +} diff --git a/JmeTests/src/jme3test/awt/TestApplet.java b/JmeTests/src/jme3test/awt/TestApplet.java new file mode 100644 index 0000000..8ac4b7f --- /dev/null +++ b/JmeTests/src/jme3test/awt/TestApplet.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.awt; + +import com.jme3.app.LegacyApplication; +import com.jme3.app.SimpleApplication; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; +import com.jme3.system.JmeSystem; +import java.applet.Applet; +import java.awt.Canvas; +import java.awt.Graphics; +import java.util.concurrent.Callable; +import javax.swing.SwingUtilities; + +public class TestApplet extends Applet { + + private static JmeCanvasContext context; + private static LegacyApplication app; + private static Canvas canvas; + private static TestApplet applet; + + public TestApplet(){ + } + + public static void createCanvas(String appClass){ + AppSettings settings = new AppSettings(true); + settings.setWidth(640); + settings.setHeight(480); +// settings.setRenderer(AppSettings.JOGL); + + JmeSystem.setLowPermissions(true); + + try{ + Class clazz = (Class) Class.forName(appClass); + app = clazz.newInstance(); + }catch (ClassNotFoundException ex){ + ex.printStackTrace(); + }catch (InstantiationException ex){ + ex.printStackTrace(); + }catch (IllegalAccessException ex){ + ex.printStackTrace(); + } + + app.setSettings(settings); + app.createCanvas(); + + context = (JmeCanvasContext) app.getContext(); + canvas = context.getCanvas(); + canvas.setSize(settings.getWidth(), settings.getHeight()); + } + + public static void startApp(){ + applet.add(canvas); + app.startCanvas(); + + app.enqueue(new Callable(){ + public Void call(){ + if (app instanceof SimpleApplication){ + SimpleApplication simpleApp = (SimpleApplication) app; + simpleApp.getFlyByCamera().setDragToRotate(true); + simpleApp.getInputManager().setCursorVisible(true); + } + return null; + } + }); + } + + public void freezeApp(){ + remove(canvas); + } + + public void unfreezeApp(){ + add(canvas); + } + + @Override + public final void update(Graphics g) { +// canvas.setSize(getWidth(), getHeight()); + } + + @Override + public void init(){ + applet = this; + createCanvas("jme3test.model.shape.TestBox"); + startApp(); + app.setPauseOnLostFocus(false); + System.out.println("applet:init"); + } + + @Override + public void start(){ +// context.setAutoFlushFrames(true); + System.out.println("applet:start"); + } + + @Override + public void stop(){ +// context.setAutoFlushFrames(false); + System.out.println("applet:stop"); + } + + @Override + public void destroy(){ + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + removeAll(); + System.out.println("applet:destroyStart"); + } + }); + app.stop(true); + System.out.println("applet:destroyEnd"); + } + +} diff --git a/JmeTests/src/jme3test/awt/TestAwtPanels.java b/JmeTests/src/jme3test/awt/TestAwtPanels.java new file mode 100644 index 0000000..5c00e50 --- /dev/null +++ b/JmeTests/src/jme3test/awt/TestAwtPanels.java @@ -0,0 +1,112 @@ +package jme3test.awt; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.system.awt.AwtPanel; +import com.jme3.system.awt.AwtPanelsContext; +import com.jme3.system.awt.PaintMode; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class TestAwtPanels extends SimpleApplication { + + final private static CountDownLatch panelsAreReady = new CountDownLatch(1); + private static TestAwtPanels app; + private static AwtPanel panel, panel2; + private static int panelsClosed = 0; + + private static void createWindowForPanel(AwtPanel panel, int location){ + JFrame frame = new JFrame("Render Display " + location); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(panel, BorderLayout.CENTER); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + if (++panelsClosed == 2){ + app.stop(); + } + } + }); + frame.pack(); + frame.setLocation(location, Toolkit.getDefaultToolkit().getScreenSize().height - 400); + frame.setVisible(true); + } + + public static void main(String[] args){ + Logger.getLogger("com.jme3").setLevel(Level.WARNING); + + app = new TestAwtPanels(); + app.setShowSettings(false); + AppSettings settings = new AppSettings(true); + settings.setCustomRenderer(AwtPanelsContext.class); + settings.setFrameRate(60); + app.setSettings(settings); + app.start(); + + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + /* + * Sleep 2 seconds to ensure there's no race condition. + * The sleep is not required for correctness. + */ + try { + Thread.sleep(2000); + } catch (InterruptedException exception) { + return; + } + + final AwtPanelsContext ctx = (AwtPanelsContext) app.getContext(); + panel = ctx.createPanel(PaintMode.Accelerated); + panel.setPreferredSize(new Dimension(400, 300)); + ctx.setInputSource(panel); + + panel2 = ctx.createPanel(PaintMode.Accelerated); + panel2.setPreferredSize(new Dimension(400, 300)); + + createWindowForPanel(panel, 300); + createWindowForPanel(panel2, 700); + /* + * Both panels are ready. + */ + panelsAreReady.countDown(); + } + }); + } + + @Override + public void simpleInitApp() { + flyCam.setDragToRotate(true); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + /* + * Wait until both AWT panels are ready. + */ + try { + panelsAreReady.await(); + } catch (InterruptedException exception) { + throw new RuntimeException("Interrupted while waiting for panels", exception); + } + + panel.attachTo(true, viewPort); + guiViewPort.setClearFlags(true, true, true); + panel2.attachTo(false, guiViewPort); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/awt/TestCanvas.java b/JmeTests/src/jme3test/awt/TestCanvas.java new file mode 100644 index 0000000..8219b49 --- /dev/null +++ b/JmeTests/src/jme3test/awt/TestCanvas.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.awt; + +import com.jme3.app.LegacyApplication; +import com.jme3.app.SimpleApplication; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; +import com.jme3.util.JmeFormatter; +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.Callable; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Logger; +import javax.swing.*; + +public class TestCanvas { + + private static JmeCanvasContext context; + private static Canvas canvas; + private static LegacyApplication app; + private static JFrame frame; + private static Container canvasPanel1, canvasPanel2; + private static Container currentPanel; + private static JTabbedPane tabbedPane; + private static final String appClass = "jme3test.post.TestRenderToTexture"; + + private static void createTabs(){ + tabbedPane = new JTabbedPane(); + + canvasPanel1 = new JPanel(); + canvasPanel1.setLayout(new BorderLayout()); + tabbedPane.addTab("jME3 Canvas 1", canvasPanel1); + + canvasPanel2 = new JPanel(); + canvasPanel2.setLayout(new BorderLayout()); + tabbedPane.addTab("jME3 Canvas 2", canvasPanel2); + + frame.getContentPane().add(tabbedPane); + + currentPanel = canvasPanel1; + } + + private static void createMenu(){ + JMenuBar menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + + JMenu menuTortureMethods = new JMenu("Canvas Torture Methods"); + menuBar.add(menuTortureMethods); + + final JMenuItem itemRemoveCanvas = new JMenuItem("Remove Canvas"); + menuTortureMethods.add(itemRemoveCanvas); + itemRemoveCanvas.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (itemRemoveCanvas.getText().equals("Remove Canvas")){ + currentPanel.remove(canvas); + + itemRemoveCanvas.setText("Add Canvas"); + }else if (itemRemoveCanvas.getText().equals("Add Canvas")){ + currentPanel.add(canvas, BorderLayout.CENTER); + + itemRemoveCanvas.setText("Remove Canvas"); + } + } + }); + + final JMenuItem itemHideCanvas = new JMenuItem("Hide Canvas"); + menuTortureMethods.add(itemHideCanvas); + itemHideCanvas.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (itemHideCanvas.getText().equals("Hide Canvas")){ + canvas.setVisible(false); + itemHideCanvas.setText("Show Canvas"); + }else if (itemHideCanvas.getText().equals("Show Canvas")){ + canvas.setVisible(true); + itemHideCanvas.setText("Hide Canvas"); + } + } + }); + + final JMenuItem itemSwitchTab = new JMenuItem("Switch to tab #2"); + menuTortureMethods.add(itemSwitchTab); + itemSwitchTab.addActionListener(new ActionListener(){ + public void actionPerformed(ActionEvent e){ + if (itemSwitchTab.getText().equals("Switch to tab #2")){ + canvasPanel1.remove(canvas); + canvasPanel2.add(canvas, BorderLayout.CENTER); + currentPanel = canvasPanel2; + itemSwitchTab.setText("Switch to tab #1"); + }else if (itemSwitchTab.getText().equals("Switch to tab #1")){ + canvasPanel2.remove(canvas); + canvasPanel1.add(canvas, BorderLayout.CENTER); + currentPanel = canvasPanel1; + itemSwitchTab.setText("Switch to tab #2"); + } + } + }); + + JMenuItem itemSwitchLaf = new JMenuItem("Switch Look and Feel"); + menuTortureMethods.add(itemSwitchLaf); + itemSwitchLaf.addActionListener(new ActionListener(){ + public void actionPerformed(ActionEvent e){ + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Throwable t){ + t.printStackTrace(); + } + SwingUtilities.updateComponentTreeUI(frame); + frame.pack(); + } + }); + + JMenuItem itemSmallSize = new JMenuItem("Set size to (0, 0)"); + menuTortureMethods.add(itemSmallSize); + itemSmallSize.addActionListener(new ActionListener(){ + public void actionPerformed(ActionEvent e){ + Dimension preferred = frame.getPreferredSize(); + frame.setPreferredSize(new Dimension(0, 0)); + frame.pack(); + frame.setPreferredSize(preferred); + } + }); + + JMenuItem itemKillCanvas = new JMenuItem("Stop/Start Canvas"); + menuTortureMethods.add(itemKillCanvas); + itemKillCanvas.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + currentPanel.remove(canvas); + app.stop(true); + + createCanvas(appClass); + currentPanel.add(canvas, BorderLayout.CENTER); + frame.pack(); + startApp(); + } + }); + + JMenuItem itemExit = new JMenuItem("Exit"); + menuTortureMethods.add(itemExit); + itemExit.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + frame.dispose(); + app.stop(); + } + }); + } + + private static void createFrame(){ + frame = new JFrame("Test"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.addWindowListener(new WindowAdapter(){ + @Override + public void windowClosed(WindowEvent e) { + app.stop(); + } + }); + + createTabs(); + createMenu(); + } + + public static void createCanvas(String appClass){ + AppSettings settings = new AppSettings(true); + settings.setWidth(640); + settings.setHeight(480); + + try{ + Class clazz = (Class) Class.forName(appClass); + app = clazz.newInstance(); + }catch (ClassNotFoundException ex){ + ex.printStackTrace(); + }catch (InstantiationException ex){ + ex.printStackTrace(); + }catch (IllegalAccessException ex){ + ex.printStackTrace(); + } + + app.setPauseOnLostFocus(false); + app.setSettings(settings); + app.createCanvas(); + app.startCanvas(); + + context = (JmeCanvasContext) app.getContext(); + canvas = context.getCanvas(); + canvas.setSize(settings.getWidth(), settings.getHeight()); + } + + public static void startApp(){ + app.startCanvas(); + app.enqueue(new Callable(){ + public Void call(){ + if (app instanceof SimpleApplication){ + SimpleApplication simpleApp = (SimpleApplication) app; + simpleApp.getFlyByCamera().setDragToRotate(true); + } + return null; + } + }); + + } + + public static void main(String[] args){ + JmeFormatter formatter = new JmeFormatter(); + + Handler consoleHandler = new ConsoleHandler(); + consoleHandler.setFormatter(formatter); + + Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]); + Logger.getLogger("").addHandler(consoleHandler); + + createCanvas(appClass); + + try { + Thread.sleep(500); + } catch (InterruptedException ex) { + } + + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + + createFrame(); + + currentPanel.add(canvas, BorderLayout.CENTER); + frame.pack(); + startApp(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + }); + } + +} diff --git a/JmeTests/src/jme3test/awt/TestSafeCanvas.java b/JmeTests/src/jme3test/awt/TestSafeCanvas.java new file mode 100644 index 0000000..6264f82 --- /dev/null +++ b/JmeTests/src/jme3test/awt/TestSafeCanvas.java @@ -0,0 +1,69 @@ +package jme3test.awt; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeCanvasContext; +import java.awt.Canvas; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JFrame; + +public class TestSafeCanvas extends SimpleApplication { + + public static void main(String[] args) throws InterruptedException{ + AppSettings settings = new AppSettings(true); + settings.setWidth(640); + settings.setHeight(480); + + final TestSafeCanvas app = new TestSafeCanvas(); + app.setPauseOnLostFocus(false); + app.setSettings(settings); + app.createCanvas(); + app.startCanvas(true); + + JmeCanvasContext context = (JmeCanvasContext) app.getContext(); + Canvas canvas = context.getCanvas(); + canvas.setSize(settings.getWidth(), settings.getHeight()); + + + + Thread.sleep(3000); + + JFrame frame = new JFrame("Test"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + app.stop(); + } + }); + frame.getContentPane().add(canvas); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + + Thread.sleep(3000); + + frame.getContentPane().remove(canvas); + + Thread.sleep(3000); + + frame.getContentPane().add(canvas); + } + + @Override + public void simpleInitApp() { + flyCam.setDragToRotate(true); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } +} diff --git a/JmeTests/src/jme3test/batching/TestBatchNode.java b/JmeTests/src/jme3test/batching/TestBatchNode.java new file mode 100644 index 0000000..db7e7a8 --- /dev/null +++ b/JmeTests/src/jme3test/batching/TestBatchNode.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.batching; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.BatchNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.system.NanoTimer; +import com.jme3.util.TangentBinormalGenerator; + +/** + * + * @author Nehon + */ +public class TestBatchNode extends SimpleApplication { + + public static void main(String[] args) { + + TestBatchNode app = new TestBatchNode(); + app.start(); + } + BatchNode batch; + WireFrustum frustum; + Geometry frustumMdl; + private Vector3f[] points; + + { + points = new Vector3f[8]; + for (int i = 0; i < points.length; i++) { + points[i] = new Vector3f(); + } + } + + @Override + public void simpleInitApp() { + timer = new NanoTimer(); + batch = new BatchNode("theBatchNode"); + + + + /** + * A cube with a color "bleeding" through transparent texture. Uses + * Texture from jme3-test-data library! + */ + Box boxshape4 = new Box(1f, 1f, 1f); + cube = new Geometry("cube1", boxshape4); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + cube.setMaterial(mat); +// Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); +// mat.setColor("Diffuse", ColorRGBA.Blue); +// mat.setBoolean("UseMaterialColors", true); + /** + * A cube with a color "bleeding" through transparent texture. Uses + * Texture from jme3-test-data library! + */ + Box box = new Box(1f, 1f, 1f); + cube2 = new Geometry("cube2", box); + cube2.setMaterial(mat); + + TangentBinormalGenerator.generate(cube); + TangentBinormalGenerator.generate(cube2); + + + n = new Node("aNode"); + // n.attachChild(cube2); + batch.attachChild(cube); + // batch.attachChild(cube2); + // batch.setMaterial(mat); + batch.batch(); + rootNode.attachChild(batch); + cube.setLocalTranslation(3, 0, 0); + cube2.setLocalTranslation(0, 20, 0); + + + updateBoindPoints(points); + frustum = new WireFrustum(points); + frustumMdl = new Geometry("f", frustum); + frustumMdl.setCullHint(Spatial.CullHint.Never); + frustumMdl.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); + frustumMdl.getMaterial().getAdditionalRenderState().setWireframe(true); + frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red); + rootNode.attachChild(frustumMdl); + dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White.mult(2)); + dl.setDirection(new Vector3f(1, -1, -1)); + rootNode.addLight(dl); + flyCam.setMoveSpeed(10); + } + Node n; + Geometry cube; + Geometry cube2; + float time = 0; + DirectionalLight dl; + boolean done = false; + + @Override + public void simpleUpdate(float tpf) { + if (!done) { + done = true; + batch.attachChild(cube2); + batch.batch(); + } + updateBoindPoints(points); + frustum.update(points); + time += tpf; + dl.setDirection(cam.getDirection()); + cube2.setLocalTranslation(FastMath.sin(-time) * 3, FastMath.cos(time) * 3, 0); + cube2.setLocalRotation(new Quaternion().fromAngleAxis(time, Vector3f.UNIT_Z)); + cube2.setLocalScale(Math.max(FastMath.sin(time), 0.5f)); + +// batch.setLocalRotation(new Quaternion().fromAngleAxis(time, Vector3f.UNIT_Z)); + + } +// + + public void updateBoindPoints(Vector3f[] points) { + BoundingBox bb = (BoundingBox) batch.getWorldBound(); + float xe = bb.getXExtent(); + float ye = bb.getYExtent(); + float ze = bb.getZExtent(); + float x = bb.getCenter().x; + float y = bb.getCenter().y; + float z = bb.getCenter().z; + + points[0].set(new Vector3f(x - xe, y - ye, z - ze)); + points[1].set(new Vector3f(x - xe, y + ye, z - ze)); + points[2].set(new Vector3f(x + xe, y + ye, z - ze)); + points[3].set(new Vector3f(x + xe, y - ye, z - ze)); + + points[4].set(new Vector3f(x + xe, y - ye, z + ze)); + points[5].set(new Vector3f(x - xe, y - ye, z + ze)); + points[6].set(new Vector3f(x - xe, y + ye, z + ze)); + points[7].set(new Vector3f(x + xe, y + ye, z + ze)); + } +} diff --git a/JmeTests/src/jme3test/batching/TestBatchNodeCluster.java b/JmeTests/src/jme3test/batching/TestBatchNodeCluster.java new file mode 100644 index 0000000..9430aa3 --- /dev/null +++ b/JmeTests/src/jme3test/batching/TestBatchNodeCluster.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.batching; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.scene.*; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.system.NanoTimer; +import java.util.ArrayList; +import java.util.Random; + +public class TestBatchNodeCluster extends SimpleApplication { + + public static void main(String[] args) { + TestBatchNodeCluster app = new TestBatchNodeCluster(); + settingst = new AppSettings(true); + //settingst.setFrameRate(75); + settingst.setResolution(640, 480); + settingst.setVSync(false); + settingst.setFullscreen(false); + app.setSettings(settingst); + app.setShowSettings(false); + app.start(); + } + private ActionListener al = new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("Start Game")) { +// randomGenerator(); + } + } + }; + protected Random rand = new Random(); + protected int maxCubes = 2000; + protected int startAt = 0; + protected static int xPositions = 0, yPositions = 0, zPositions = 0; + protected int returner = 0; + protected ArrayList xPosition = new ArrayList(); + protected ArrayList yPosition = new ArrayList(); + protected ArrayList zPosition = new ArrayList(); + protected int xLimitf = 60, xLimits = -60, yLimitf = 60, yLimits = -20, zLimitf = 60, zLimits = -60; + protected int circ = 8;//increases by 8 every time. + protected int dynamic = 4; + protected static AppSettings settingst; + protected boolean isTrue = true; + private int lineLength = 50; + protected BatchNode batchNode; + Material mat1; + Material mat2; + Material mat3; + Material mat4; + Node terrain; + //protected +// protected Geometry player; + + @Override + public void simpleInitApp() { + timer = new NanoTimer(); + + batchNode = new SimpleBatchNode("BatchNode"); + + + xPosition.add(0); + yPosition.add(0); + zPosition.add(0); + + mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.White); + mat1.setColor("GlowColor", ColorRGBA.Blue.mult(10)); + + mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setColor("Color", ColorRGBA.White); + mat2.setColor("GlowColor", ColorRGBA.Red.mult(10)); + + mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat3.setColor("Color", ColorRGBA.White); + mat3.setColor("GlowColor", ColorRGBA.Yellow.mult(10)); + + mat4 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat4.setColor("Color", ColorRGBA.White); + mat4.setColor("GlowColor", ColorRGBA.Orange.mult(10)); + + randomGenerator(); + + //rootNode.attachChild(SkyFactory.createSky( + // assetManager, "Textures/SKY02.zip", false)); + inputManager.addMapping("Start Game", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addListener(al, new String[]{"Start Game"}); + + + cam.setLocation(new Vector3f(-34.403286f, 126.65158f, 434.791f)); + cam.setRotation(new Quaternion(0.022630932f, 0.9749435f, -0.18736298f, 0.11776358f)); + + + batchNode.batch(); + + + terrain = new Node("terrain"); + terrain.setLocalTranslation(50, 0, 50); + terrain.attachChild(batchNode); + + flyCam.setMoveSpeed(100); + rootNode.attachChild(terrain); + Vector3f pos = new Vector3f(-40, 0, -40); + batchNode.setLocalTranslation(pos); + + + Arrow a = new Arrow(new Vector3f(0, 50, 0)); + Geometry g = new Geometry("a", a); + g.setLocalTranslation(terrain.getLocalTranslation()); + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setColor("Color", ColorRGBA.Blue); + g.setMaterial(m); + + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(new BloomFilter(BloomFilter.GlowMode.Objects)); +// SSAOFilter ssao = new SSAOFilter(8.630104f,22.970434f,2.9299977f,0.2999997f); +// fpp.addFilter(ssao); + viewPort.addProcessor(fpp); + // viewPort.setBackgroundColor(ColorRGBA.DarkGray); + } + + public void randomGenerator() { + for (int i = startAt; i < maxCubes - 1; i++) { + randomize(); + Geometry box = new Geometry("Box" + i, new Box(1, 1, 1)); + box.setLocalTranslation(new Vector3f(xPosition.get(xPosition.size() - 1), + yPosition.get(yPosition.size() - 1), + zPosition.get(zPosition.size() - 1))); + batchNode.attachChild(box); + if (i < 500) { + box.setMaterial(mat1); + } else if (i < 1000) { + + box.setMaterial(mat2); + } else if (i < 1500) { + + box.setMaterial(mat3); + } else { + + box.setMaterial(mat4); + } + + } + } + +// public BatchNode randomBatch() { +// +// int randomn = rand.nextInt(4); +// if (randomn == 0) { +// return blue; +// } else if (randomn == 1) { +// return brown; +// } else if (randomn == 2) { +// return pink; +// } else if (randomn == 3) { +// return orange; +// } +// return null; +// } + public ColorRGBA randomColor() { + ColorRGBA color = ColorRGBA.Black; + int randomn = rand.nextInt(4); + if (randomn == 0) { + color = ColorRGBA.Orange; + } else if (randomn == 1) { + color = ColorRGBA.Blue; + } else if (randomn == 2) { + color = ColorRGBA.Brown; + } else if (randomn == 3) { + color = ColorRGBA.Magenta; + } + return color; + } + + public void randomize() { + int xpos = xPosition.get(xPosition.size() - 1); + int ypos = yPosition.get(yPosition.size() - 1); + int zpos = zPosition.get(zPosition.size() - 1); + int x = 0; + int y = 0; + int z = 0; + boolean unTrue = true; + while (unTrue) { + unTrue = false; + boolean xChanged = false; + x = 0; + y = 0; + z = 0; + if (xpos >= lineLength * 2) { + x = 2; + xChanged = true; + } else { + x = xPosition.get(xPosition.size() - 1) + 2; + } + if (xChanged) { + //y = yPosition.get(yPosition.size() - lineLength) + 2; + } else { + y = rand.nextInt(3); + if (yPosition.size() > lineLength) { + if (yPosition.size() > 51) { + if (y == 0 && ypos < yLimitf && getym(lineLength) > ypos - 2) { + y = ypos + 2; + } else if (y == 1 && ypos > yLimits && getym(lineLength) < ypos + 2) { + y = ypos - 2; + } else if (y == 2 && getym(lineLength) > ypos - 2 && getym(lineLength) < ypos + 2) { + y = ypos; + } else { + if (ypos >= yLimitf) { + y = ypos - 2; + } else if (ypos <= yLimits) { + y = ypos + 2; + } else if (y == 0 && getym(lineLength) >= ypos - 4) { + y = ypos - 2; + } else if (y == 0 && getym(lineLength) >= ypos - 2) { + y = ypos; + } else if (y == 1 && getym(lineLength) >= ypos + 4) { + y = ypos + 2; + } else if (y == 1 && getym(lineLength) >= ypos + 2) { + y = ypos; + } else if (y == 2 && getym(lineLength) <= ypos - 2) { + y = ypos - 2; + } else if (y == 2 && getym(lineLength) >= ypos + 2) { + y = ypos + 2; + } else { + System.out.println("wtf"); + } + } + } else if (yPosition.size() == lineLength) { + if (y == 0 && ypos < yLimitf) { + y = getym(lineLength) + 2; + } else if (y == 1 && ypos > yLimits) { + y = getym(lineLength) - 2; + } + } + } else { + if (y == 0 && ypos < yLimitf) { + y = ypos + 2; + } else if (y == 1 && ypos > yLimits) { + y = ypos - 2; + } else if (y == 2) { + y = ypos; + } else if (y == 0 && ypos >= yLimitf) { + y = ypos - 2; + } else if (y == 1 && ypos <= yLimits) { + y = ypos + 2; + } + } + } + if (xChanged) { + z = zpos + 2; + } else { + z = zpos; + } +// for (int i = 0; i < xPosition.size(); i++) +// { +// if (x - xPosition.get(i) <= 1 && x - xPosition.get(i) >= -1 && +// y - yPosition.get(i) <= 1 && y - yPosition.get(i) >= -1 +// &&z - zPosition.get(i) <= 1 && z - zPosition.get(i) >= +// -1) +// { +// unTrue = true; +// } +// } + } + xPosition.add(x); + yPosition.add(y); + zPosition.add(z); + } + + public int getxm(int i) { + return xPosition.get(xPosition.size() - i); + } + + public int getym(int i) { + return yPosition.get(yPosition.size() - i); + } + + public int getzm(int i) { + return zPosition.get(zPosition.size() - i); + } + + public int getx(int i) { + return xPosition.get(i); + } + + public int gety(int i) { + return yPosition.get(i); + } + + public int getz(int i) { + return zPosition.get(i); + } + long nbFrames = 0; + long cullTime = 0; + float time = 0; + Vector3f lookAtPos = new Vector3f(0, 0, 0); + float xpos = 0; + Spatial box; + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + int random = rand.nextInt(2000); + float mult1 = 1.0f; + float mult2 = 1.0f; + if (random < 500) { + mult1 = 1.0f; + mult2 = 1.0f; + } else if (random < 1000) { + mult1 = -1.0f; + mult2 = 1.0f; + } else if (random < 1500) { + mult1 = 1.0f; + mult2 = -1.0f; + } else if (random <= 2000) { + mult1 = -1.0f; + mult2 = -1.0f; + } + box = batchNode.getChild("Box" + random); + if (box != null) { + Vector3f v = box.getLocalTranslation(); + box.setLocalTranslation(v.x + FastMath.sin(time * mult1) * 20, v.y + (FastMath.sin(time * mult1) * FastMath.cos(time * mult1) * 20), v.z + FastMath.cos(time * mult2) * 20); + } + terrain.setLocalRotation(new Quaternion().fromAngleAxis(time, Vector3f.UNIT_Y)); + + + } +} diff --git a/JmeTests/src/jme3test/batching/TestBatchNodeTower.java b/JmeTests/src/jme3test/batching/TestBatchNodeTower.java new file mode 100644 index 0000000..a13dc61 --- /dev/null +++ b/JmeTests/src/jme3test/batching/TestBatchNodeTower.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.batching; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.BatchNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.shadow.CompareMode; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.system.AppSettings; +import com.jme3.system.NanoTimer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import jme3test.bullet.BombControl; + +/** + * + * @author double1984 (tower mod by atom) + */ +public class TestBatchNodeTower extends SimpleApplication { + + int bricksPerLayer = 8; + int brickLayers = 30; + + static float brickWidth = .75f, brickHeight = .25f, brickDepth = .25f; + float radius = 3f; + float angle = 0; + + + Material mat; + Material mat2; + Material mat3; + DirectionalLightShadowFilter shadowRenderer; + private Sphere bullet; + private Box brick; + private SphereCollisionShape bulletCollisionShape; + + private BulletAppState bulletAppState; + BatchNode batchNode = new BatchNode("batch Node"); + + public static void main(String args[]) { + TestBatchNodeTower f = new TestBatchNodeTower(); + AppSettings s = new AppSettings(true); + f.setSettings(s); + f.start(); + } + + @Override + public void simpleInitApp() { + timer = new NanoTimer(); + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + // bulletAppState.setEnabled(false); + stateManager.attach(bulletAppState); + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.4f); + + brick = new Box(brickWidth, brickHeight, brickDepth); + brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); + initMaterial(); + initTower(); + initFloor(); + initCrossHairs(); + this.cam.setLocation(new Vector3f(0, 25f, 8f)); + cam.lookAt(Vector3f.ZERO, new Vector3f(0, 1, 0)); + cam.setFrustumFar(80); + inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "shoot"); + rootNode.setShadowMode(ShadowMode.Off); + + batchNode.batch(); + batchNode.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(batchNode); + + + shadowRenderer = new DirectionalLightShadowFilter(assetManager, 1024, 2); + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + shadowRenderer.setLight(dl); + shadowRenderer.setLambda(0.55f); + shadowRenderer.setShadowIntensity(0.6f); + shadowRenderer.setShadowCompareMode(CompareMode.Hardware); + shadowRenderer.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(shadowRenderer); + viewPort.addProcessor(fpp); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("shoot") && !keyPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat2); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.setLocalTranslation(cam.getLocation()); + RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); +// RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, 1); + bulletNode.setLinearVelocity(cam.getDirection().mult(25)); + bulletg.addControl(bulletNode); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletNode); + } + } + }; + + public void initTower() { + double tempX = 0; + double tempY = 0; + double tempZ = 0; + angle = 0f; + for (int i = 0; i < brickLayers; i++){ + // Increment rows + if (i != 0) { + tempY += brickHeight * 2; + } else { + tempY = brickHeight; + } + // Alternate brick seams + angle = 360.0f / bricksPerLayer * i/2f; + for (int j = 0; j < bricksPerLayer; j++){ + tempZ = Math.cos(Math.toRadians(angle))*radius; + tempX = Math.sin(Math.toRadians(angle))*radius; + System.out.println("x="+((float)(tempX))+" y="+((float)(tempY))+" z="+(float)(tempZ)); + Vector3f vt = new Vector3f((float)(tempX), (float)(tempY), (float)(tempZ)); + // Add crenelation + if (i==brickLayers-1){ + if (j%2 == 0){ + addBrick(vt); + } + } + // Create main tower + else { + addBrick(vt); + } + angle += 360.0/bricksPerLayer; + } + } + + } + + public void initFloor() { + Box floorBox = new Box(10f, 0.1f, 5f); + floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); + + Geometry floor = new Geometry("floor", floorBox); + floor.setMaterial(mat3); + floor.setShadowMode(ShadowMode.Receive); + floor.setLocalTranslation(0, 0, 0); + floor.addControl(new RigidBodyControl(0)); + this.rootNode.attachChild(floor); + this.getPhysicsSpace().add(floor); + } + + public void initMaterial() { + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + mat.setTexture("ColorMap", tex); + + mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = assetManager.loadTexture(key2); + mat2.setTexture("ColorMap", tex2); + + mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); + key3.setGenerateMips(true); + Texture tex3 = assetManager.loadTexture(key3); + tex3.setWrap(WrapMode.Repeat); + mat3.setTexture("ColorMap", tex3); + } +int nbBrick =0; + public void addBrick(Vector3f ori) { + Geometry reBoxg = new Geometry("brick", brick); + reBoxg.setMaterial(mat); + reBoxg.setLocalTranslation(ori); + reBoxg.rotate(0f, (float)Math.toRadians(angle) , 0f ); + reBoxg.addControl(new RigidBodyControl(1.5f)); + reBoxg.setShadowMode(ShadowMode.CastAndReceive); + reBoxg.getControl(RigidBodyControl.class).setFriction(1.6f); + this.batchNode.attachChild(reBoxg); + this.getPhysicsSpace().add(reBoxg); + nbBrick++; + } + + protected void initCrossHairs() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2, + settings.getHeight() / 2 + ch.getLineHeight() / 2, 0); + guiNode.attachChild(ch); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/blender/TestBlenderLoader.java b/JmeTests/src/jme3test/blender/TestBlenderLoader.java new file mode 100644 index 0000000..0ff740b --- /dev/null +++ b/JmeTests/src/jme3test/blender/TestBlenderLoader.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.blender; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; + +public class TestBlenderLoader extends SimpleApplication { + + public static void main(String[] args){ + TestBlenderLoader app = new TestBlenderLoader(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + //load model with packed images + Spatial ogre = assetManager.loadModel("Blender/2.4x/Sinbad.blend"); + rootNode.attachChild(ogre); + + //load model with referenced images + Spatial track = assetManager.loadModel("Blender/2.4x/MountainValley_Track.blend"); + rootNode.attachChild(track); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f)); + rootNode.addLight(dl); + + // skylight + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f)); + rootNode.addLight(dl); + + // white ambient light + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.80f, 0.70f, 0.80f, 1.0f)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + } + +} diff --git a/JmeTests/src/jme3test/bounding/TestRayCollision.java b/JmeTests/src/jme3test/bounding/TestRayCollision.java new file mode 100644 index 0000000..8396284 --- /dev/null +++ b/JmeTests/src/jme3test/bounding/TestRayCollision.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bounding; + +import com.jme3.bounding.BoundingBox; +import com.jme3.collision.CollisionResults; +import com.jme3.math.Ray; +import com.jme3.math.Vector3f; + +/** + * Tests picking/collision between bounds and shapes. + */ +public class TestRayCollision { + + public static void main(String[] args){ + Ray r = new Ray(Vector3f.ZERO, Vector3f.UNIT_X); + BoundingBox bbox = new BoundingBox(new Vector3f(5, 0, 0), 1, 1, 1); + + CollisionResults res = new CollisionResults(); + bbox.collideWith(r, res); + + System.out.println("Bounding:" +bbox); + System.out.println("Ray: "+r); + + System.out.println("Num collisions: "+res.size()); + for (int i = 0; i < res.size(); i++){ + System.out.println("--- Collision #"+i+" ---"); + float dist = res.getCollision(i).getDistance(); + Vector3f pt = res.getCollision(i).getContactPoint(); + System.out.println("distance: "+dist); + System.out.println("point: "+pt); + } + } + +} diff --git a/JmeTests/src/jme3test/bullet/BombControl.java b/JmeTests/src/jme3test/bullet/BombControl.java new file mode 100644 index 0000000..4d9af6a --- /dev/null +++ b/JmeTests/src/jme3test/bullet/BombControl.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.asset.AssetManager; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.PhysicsTickListener; +import com.jme3.bullet.collision.PhysicsCollisionEvent; +import com.jme3.bullet.collision.PhysicsCollisionListener; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.objects.PhysicsGhostObject; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import java.io.IOException; +import java.util.Iterator; + +/** + * + * @author normenhansen + */ +public class BombControl extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener { + + private float explosionRadius = 10; + private PhysicsGhostObject ghostObject; + private Vector3f vector = new Vector3f(); + private Vector3f vector2 = new Vector3f(); + private float forceFactor = 1; + private ParticleEmitter effect; + private float fxTime = 0.5f; + private float maxTime = 4f; + private float curTime = -1.0f; + private float timer; + + public BombControl(CollisionShape shape, float mass) { + super(shape, mass); + createGhostObject(); + } + + public BombControl(AssetManager manager, CollisionShape shape, float mass) { + super(shape, mass); + createGhostObject(); + prepareEffect(manager); + } + + public void setPhysicsSpace(PhysicsSpace space) { + super.setPhysicsSpace(space); + if (space != null) { + space.addCollisionListener(this); + } + } + + private void prepareEffect(AssetManager assetManager) { + int COUNT_FACTOR = 1; + float COUNT_FACTOR_F = 1f; + effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR); + effect.setSelectRandomImage(true); + effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F))); + effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f)); + effect.setStartSize(1.3f); + effect.setEndSize(2f); + effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); + effect.setParticlesPerSec(0); + effect.setGravity(0, -5f, 0); + effect.setLowLife(.4f); + effect.setHighLife(.5f); + effect.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 7, 0)); + effect.getParticleInfluencer().setVelocityVariation(1f); + effect.setImagesX(2); + effect.setImagesY(2); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + effect.setMaterial(mat); + } + + protected void createGhostObject() { + ghostObject = new PhysicsGhostObject(new SphereCollisionShape(explosionRadius)); + } + + public void collision(PhysicsCollisionEvent event) { + if (space == null) { + return; + } + if (event.getObjectA() == this || event.getObjectB() == this) { + space.add(ghostObject); + ghostObject.setPhysicsLocation(getPhysicsLocation(vector)); + space.addTickListener(this); + if (effect != null && spatial.getParent() != null) { + curTime = 0; + effect.setLocalTranslation(spatial.getLocalTranslation()); + spatial.getParent().attachChild(effect); + effect.emitAllParticles(); + } + space.remove(this); + spatial.removeFromParent(); + } + } + + public void prePhysicsTick(PhysicsSpace space, float f) { + space.removeCollisionListener(this); + } + + public void physicsTick(PhysicsSpace space, float f) { + //get all overlapping objects and apply impulse to them + for (Iterator it = ghostObject.getOverlappingObjects().iterator(); it.hasNext();) { + PhysicsCollisionObject physicsCollisionObject = it.next(); + if (physicsCollisionObject instanceof PhysicsRigidBody) { + PhysicsRigidBody rBody = (PhysicsRigidBody) physicsCollisionObject; + rBody.getPhysicsLocation(vector2); + vector2.subtractLocal(vector); + float force = explosionRadius - vector2.length(); + force *= forceFactor; + force = force > 0 ? force : 0; + vector2.normalizeLocal(); + vector2.multLocal(force); + ((PhysicsRigidBody) physicsCollisionObject).applyImpulse(vector2, Vector3f.ZERO); + } + } + space.removeTickListener(this); + space.remove(ghostObject); + } + + @Override + public void update(float tpf) { + super.update(tpf); + if(enabled){ + timer+=tpf; + if(timer>maxTime){ + if(spatial.getParent()!=null){ + space.removeCollisionListener(this); + space.remove(this); + spatial.removeFromParent(); + } + } + } + if (enabled && curTime >= 0) { + curTime += tpf; + if (curTime > fxTime) { + curTime = -1; + effect.removeFromParent(); + } + } + } + + /** + * @return the explosionRadius + */ + public float getExplosionRadius() { + return explosionRadius; + } + + /** + * @param explosionRadius the explosionRadius to set + */ + public void setExplosionRadius(float explosionRadius) { + this.explosionRadius = explosionRadius; + createGhostObject(); + } + + public float getForceFactor() { + return forceFactor; + } + + public void setForceFactor(float forceFactor) { + this.forceFactor = forceFactor; + } + + + @Override + public void read(JmeImporter im) throws IOException { + throw new UnsupportedOperationException("Reading not supported."); + } + + @Override + public void write(JmeExporter ex) throws IOException { + throw new UnsupportedOperationException("Saving not supported."); + } +} diff --git a/JmeTests/src/jme3test/bullet/PhysicsHoverControl.java b/JmeTests/src/jme3test/bullet/PhysicsHoverControl.java new file mode 100644 index 0000000..a286501 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/PhysicsHoverControl.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.PhysicsTickListener; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.objects.PhysicsVehicle; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; +import java.io.IOException; + +/** + * PhysicsHoverControl uses a RayCast Vehicle with "slippery wheels" to simulate a hovering tank + * @author normenhansen + */ +public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener, JmeCloneable { + + protected Spatial spatial; + protected boolean enabled = true; + protected PhysicsSpace space = null; + protected float steeringValue = 0; + protected float accelerationValue = 0; + protected int xw = 3; + protected int zw = 5; + protected int yw = 2; + protected Vector3f HOVER_HEIGHT_LF_START = new Vector3f(xw, 1, zw); + protected Vector3f HOVER_HEIGHT_RF_START = new Vector3f(-xw, 1, zw); + protected Vector3f HOVER_HEIGHT_LR_START = new Vector3f(xw, 1, -zw); + protected Vector3f HOVER_HEIGHT_RR_START = new Vector3f(-xw, 1, -zw); + protected Vector3f HOVER_HEIGHT_LF = new Vector3f(xw, -yw, zw); + protected Vector3f HOVER_HEIGHT_RF = new Vector3f(-xw, -yw, zw); + protected Vector3f HOVER_HEIGHT_LR = new Vector3f(xw, -yw, -zw); + protected Vector3f HOVER_HEIGHT_RR = new Vector3f(-xw, -yw, -zw); + protected Vector3f tempVect1 = new Vector3f(0, 0, 0); + protected Vector3f tempVect2 = new Vector3f(0, 0, 0); + protected Vector3f tempVect3 = new Vector3f(0, 0, 0); +// protected float rotationCounterForce = 10000f; +// protected float speedCounterMult = 2000f; +// protected float multiplier = 1000f; + + public PhysicsHoverControl() { + } + + /** + * Creates a new PhysicsNode with the supplied collision shape + * @param shape + */ + public PhysicsHoverControl(CollisionShape shape) { + super(shape); + createWheels(); + } + + public PhysicsHoverControl(CollisionShape shape, float mass) { + super(shape, mass); + createWheels(); + } + + @Override + public Control cloneForSpatial(Spatial spatial) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object jmeClone() { + throw new UnsupportedOperationException("Not yet implemented."); + } + + @Override + public void cloneFields( Cloner cloner, Object original ) { + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setSpatial(Spatial spatial) { + this.spatial = spatial; + setUserObject(spatial); + if (spatial == null) { + return; + } + setPhysicsLocation(spatial.getWorldTranslation()); + setPhysicsRotation(spatial.getWorldRotation().toRotationMatrix()); + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + private void createWheels() { + addWheel(HOVER_HEIGHT_LF_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false); + addWheel(HOVER_HEIGHT_RF_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false); + addWheel(HOVER_HEIGHT_LR_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false); + addWheel(HOVER_HEIGHT_RR_START, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), yw, yw, false); + for (int i = 0; i < 4; i++) { + getWheel(i).setFrictionSlip(0.001f); + } + } + + public void prePhysicsTick(PhysicsSpace space, float f) { + Vector3f angVel = getAngularVelocity(); + float rotationVelocity = angVel.getY(); + Vector3f dir = getForwardVector(tempVect2).multLocal(1, 0, 1).normalizeLocal(); + getLinearVelocity(tempVect3); + Vector3f linearVelocity = tempVect3.multLocal(1, 0, 1); + + if (steeringValue != 0) { + if (rotationVelocity < 1 && rotationVelocity > -1) { + applyTorque(tempVect1.set(0, steeringValue, 0)); + } + } else { + // counter the steering value! + if (rotationVelocity > 0.2f) { + applyTorque(tempVect1.set(0, -mass * 20, 0)); + } else if (rotationVelocity < -0.2f) { + applyTorque(tempVect1.set(0, mass * 20, 0)); + } + } + if (accelerationValue > 0) { + // counter force that will adjust velocity + // if we are not going where we want to go. + // this will prevent "drifting" and thus improve control + // of the vehicle + float d = dir.dot(linearVelocity.normalize()); + Vector3f counter = dir.project(linearVelocity).normalizeLocal().negateLocal().multLocal(1 - d); + applyForce(counter.multLocal(mass * 10), Vector3f.ZERO); + + if (linearVelocity.length() < 30) { + applyForce(dir.multLocal(accelerationValue), Vector3f.ZERO); + } + } else { + // counter the acceleration value + if (linearVelocity.length() > FastMath.ZERO_TOLERANCE) { + linearVelocity.normalizeLocal().negateLocal(); + applyForce(linearVelocity.mult(mass * 10), Vector3f.ZERO); + } + } + } + + public void physicsTick(PhysicsSpace space, float f) { + } + + public void update(float tpf) { + if (enabled && spatial != null) { + getMotionState().applyTransform(spatial); + } + } + + public void render(RenderManager rm, ViewPort vp) { + } + + public void setPhysicsSpace(PhysicsSpace space) { + createVehicle(space); + if (space == null) { + if (this.space != null) { + this.space.removeCollisionObject(this); + this.space.removeTickListener(this); + } + this.space = space; + } else { + space.addCollisionObject(this); + space.addTickListener(this); + } + this.space = space; + } + + public PhysicsSpace getPhysicsSpace() { + return space; + } + + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(enabled, "enabled", true); + oc.write(spatial, "spatial", null); + } + + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + enabled = ic.readBoolean("enabled", true); + spatial = (Spatial) ic.readSavable("spatial", null); + } + + /** + * @param steeringValue the steeringValue to set + */ + @Override + public void steer(float steeringValue) { + this.steeringValue = steeringValue * getMass(); + } + + /** + * @param accelerationValue the accelerationValue to set + */ + @Override + public void accelerate(float accelerationValue) { + this.accelerationValue = accelerationValue * getMass(); + } + +} diff --git a/JmeTests/src/jme3test/bullet/PhysicsTestHelper.java b/JmeTests/src/jme3test/bullet/PhysicsTestHelper.java new file mode 100644 index 0000000..531331d --- /dev/null +++ b/JmeTests/src/jme3test/bullet/PhysicsTestHelper.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.Application; +import com.jme3.asset.AssetManager; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.texture.Texture; + +/** + * + * @author normenhansen + */ +public class PhysicsTestHelper { + + /** + * creates a simple physics test world with a floor, an obstacle and some test boxes + * @param rootNode + * @param assetManager + * @param space + */ + public static void createPhysicsTestWorld(Node rootNode, AssetManager assetManager, PhysicsSpace space) { + AmbientLight light = new AmbientLight(); + light.setColor(ColorRGBA.LightGray); + rootNode.addLight(light); + + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + + Box floorBox = new Box(140, 0.25f, 140); + Geometry floorGeometry = new Geometry("Floor", floorBox); + floorGeometry.setMaterial(material); + floorGeometry.setLocalTranslation(0, -5, 0); +// Plane plane = new Plane(); +// plane.setOriginNormal(new Vector3f(0, 0.25f, 0), Vector3f.UNIT_Y); +// floorGeometry.addControl(new RigidBodyControl(new PlaneCollisionShape(plane), 0)); + floorGeometry.addControl(new RigidBodyControl(0)); + rootNode.attachChild(floorGeometry); + space.add(floorGeometry); + + //movable boxes + for (int i = 0; i < 12; i++) { + Box box = new Box(0.25f, 0.25f, 0.25f); + Geometry boxGeometry = new Geometry("Box", box); + boxGeometry.setMaterial(material); + boxGeometry.setLocalTranslation(i, 5, -3); + //RigidBodyControl automatically uses box collision shapes when attached to single geometry with box mesh + boxGeometry.addControl(new RigidBodyControl(2)); + rootNode.attachChild(boxGeometry); + space.add(boxGeometry); + } + + //immovable sphere with mesh collision shape + Sphere sphere = new Sphere(8, 8, 1); + Geometry sphereGeometry = new Geometry("Sphere", sphere); + sphereGeometry.setMaterial(material); + sphereGeometry.setLocalTranslation(4, -4, 2); + sphereGeometry.addControl(new RigidBodyControl(new MeshCollisionShape(sphere), 0)); + rootNode.attachChild(sphereGeometry); + space.add(sphereGeometry); + + } + + public static void createPhysicsTestWorldSoccer(Node rootNode, AssetManager assetManager, PhysicsSpace space) { + AmbientLight light = new AmbientLight(); + light.setColor(ColorRGBA.LightGray); + rootNode.addLight(light); + + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + + Box floorBox = new Box(20, 0.25f, 20); + Geometry floorGeometry = new Geometry("Floor", floorBox); + floorGeometry.setMaterial(material); + floorGeometry.setLocalTranslation(0, -0.25f, 0); +// Plane plane = new Plane(); +// plane.setOriginNormal(new Vector3f(0, 0.25f, 0), Vector3f.UNIT_Y); +// floorGeometry.addControl(new RigidBodyControl(new PlaneCollisionShape(plane), 0)); + floorGeometry.addControl(new RigidBodyControl(0)); + rootNode.attachChild(floorGeometry); + space.add(floorGeometry); + + //movable spheres + for (int i = 0; i < 5; i++) { + Sphere sphere = new Sphere(16, 16, .5f); + Geometry ballGeometry = new Geometry("Soccer ball", sphere); + ballGeometry.setMaterial(material); + ballGeometry.setLocalTranslation(i, 2, -3); + //RigidBodyControl automatically uses Sphere collision shapes when attached to single geometry with sphere mesh + ballGeometry.addControl(new RigidBodyControl(.001f)); + ballGeometry.getControl(RigidBodyControl.class).setRestitution(1); + rootNode.attachChild(ballGeometry); + space.add(ballGeometry); + } + { + //immovable Box with mesh collision shape + Box box = new Box(1, 1, 1); + Geometry boxGeometry = new Geometry("Box", box); + boxGeometry.setMaterial(material); + boxGeometry.setLocalTranslation(4, 1, 2); + boxGeometry.addControl(new RigidBodyControl(new MeshCollisionShape(box), 0)); + rootNode.attachChild(boxGeometry); + space.add(boxGeometry); + } + { + //immovable Box with mesh collision shape + Box box = new Box(1, 1, 1); + Geometry boxGeometry = new Geometry("Box", box); + boxGeometry.setMaterial(material); + boxGeometry.setLocalTranslation(4, 3, 4); + boxGeometry.addControl(new RigidBodyControl(new MeshCollisionShape(box), 0)); + rootNode.attachChild(boxGeometry); + space.add(boxGeometry); + } + } + + /** + * creates a box geometry with a RigidBodyControl + * @param assetManager + * @return + */ + public static Geometry createPhysicsTestBox(AssetManager assetManager) { + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Box box = new Box(0.25f, 0.25f, 0.25f); + Geometry boxGeometry = new Geometry("Box", box); + boxGeometry.setMaterial(material); + //RigidBodyControl automatically uses box collision shapes when attached to single geometry with box mesh + boxGeometry.addControl(new RigidBodyControl(2)); + return boxGeometry; + } + + /** + * creates a sphere geometry with a RigidBodyControl + * @param assetManager + * @return + */ + public static Geometry createPhysicsTestSphere(AssetManager assetManager) { + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Sphere sphere = new Sphere(8, 8, 0.25f); + Geometry boxGeometry = new Geometry("Sphere", sphere); + boxGeometry.setMaterial(material); + //RigidBodyControl automatically uses sphere collision shapes when attached to single geometry with sphere mesh + boxGeometry.addControl(new RigidBodyControl(2)); + return boxGeometry; + } + + /** + * creates an empty node with a RigidBodyControl + * @param manager + * @param shape + * @param mass + * @return + */ + public static Node createPhysicsTestNode(AssetManager manager, CollisionShape shape, float mass) { + Node node = new Node("PhysicsNode"); + RigidBodyControl control = new RigidBodyControl(shape, mass); + node.addControl(control); + return node; + } + + /** + * creates the necessary inputlistener and action to shoot balls from the camera + * @param app + * @param rootNode + * @param space + */ + public static void createBallShooter(final Application app, final Node rootNode, final PhysicsSpace space) { + ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + Sphere bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + Material mat2 = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = app.getAssetManager().loadTexture(key2); + mat2.setTexture("ColorMap", tex2); + if (name.equals("shoot") && !keyPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat2); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.setLocalTranslation(app.getCamera().getLocation()); + RigidBodyControl bulletControl = new RigidBodyControl(10); + bulletg.addControl(bulletControl); + bulletControl.setLinearVelocity(app.getCamera().getDirection().mult(25)); + bulletg.addControl(bulletControl); + rootNode.attachChild(bulletg); + space.add(bulletControl); + } + } + }; + app.getInputManager().addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + app.getInputManager().addListener(actionListener, "shoot"); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestAttachDriver.java b/JmeTests/src/jme3test/bullet/TestAttachDriver.java new file mode 100644 index 0000000..1de5b01 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestAttachDriver.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CompoundCollisionShape; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.joints.SliderJoint; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Cylinder; +import com.jme3.texture.Texture; + +/** + * Tests attaching/detaching nodes via joints + * @author normenhansen + */ +public class TestAttachDriver extends SimpleApplication implements ActionListener { + + private VehicleControl vehicle; + private RigidBodyControl driver; + private RigidBodyControl bridge; + private SliderJoint slider; + private final float accelerationForce = 1000.0f; + private final float brakeForce = 100.0f; + private float steeringValue = 0; + private float accelerationValue = 0; + private Vector3f jumpForce = new Vector3f(0, 3000, 0); + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestAttachDriver app = new TestAttachDriver(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + setupKeys(); + setupFloor(); + buildPlayer(); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Lefts"); + inputManager.addListener(this, "Rights"); + inputManager.addListener(this, "Ups"); + inputManager.addListener(this, "Downs"); + inputManager.addListener(this, "Space"); + inputManager.addListener(this, "Reset"); + } + + public void setupFloor() { + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Interface/Logo/Monkey.jpg", true); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + tex.setMinFilter(Texture.MinFilter.Trilinear); + mat.setTexture("ColorMap", tex); + + Box floor = new Box(100, 1f, 100); + Geometry floorGeom = new Geometry("Floor", floor); + floorGeom.setMaterial(mat); + floorGeom.setLocalTranslation(new Vector3f(0f, -3, 0f)); + + floorGeom.addControl(new RigidBodyControl(new MeshCollisionShape(floorGeom.getMesh()), 0)); + rootNode.attachChild(floorGeom); + getPhysicsSpace().add(floorGeom); + } + + private void buildPlayer() { + Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", ColorRGBA.Red); + + //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0 + //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0 + CompoundCollisionShape compoundShape = new CompoundCollisionShape(); + BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f)); + compoundShape.addChildShape(box, new Vector3f(0, 1, 0)); + + //create vehicle node + Node vehicleNode=new Node("vehicleNode"); + vehicle = new VehicleControl(compoundShape, 800); + vehicleNode.addControl(vehicle); + + //setting suspension values for wheels, this can be a bit tricky + //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en + float stiffness = 60.0f;//200=f1 car + float compValue = .3f; //(should be lower than damp) + float dampValue = .4f; + vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness)); + vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness)); + vehicle.setSuspensionStiffness(stiffness); + vehicle.setMaxSuspensionForce(10000.0f); + + //Create four wheels and add them at their locations + Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0 + Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0 + float radius = 0.5f; + float restLength = 0.3f; + float yOff = 0.5f; + float xOff = 1f; + float zOff = 2f; + + Cylinder wheelMesh = new Cylinder(16, 16, radius, radius * 0.6f, true); + + Node node1 = new Node("wheel 1 node"); + Geometry wheels1 = new Geometry("wheel 1", wheelMesh); + node1.attachChild(wheels1); + wheels1.rotate(0, FastMath.HALF_PI, 0); + wheels1.setMaterial(mat); + vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff), + wheelDirection, wheelAxle, restLength, radius, true); + + Node node2 = new Node("wheel 2 node"); + Geometry wheels2 = new Geometry("wheel 2", wheelMesh); + node2.attachChild(wheels2); + wheels2.rotate(0, FastMath.HALF_PI, 0); + wheels2.setMaterial(mat); + vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff), + wheelDirection, wheelAxle, restLength, radius, true); + + Node node3 = new Node("wheel 3 node"); + Geometry wheels3 = new Geometry("wheel 3", wheelMesh); + node3.attachChild(wheels3); + wheels3.rotate(0, FastMath.HALF_PI, 0); + wheels3.setMaterial(mat); + vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff), + wheelDirection, wheelAxle, restLength, radius, false); + + Node node4 = new Node("wheel 4 node"); + Geometry wheels4 = new Geometry("wheel 4", wheelMesh); + node4.attachChild(wheels4); + wheels4.rotate(0, FastMath.HALF_PI, 0); + wheels4.setMaterial(mat); + vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff), + wheelDirection, wheelAxle, restLength, radius, false); + + vehicleNode.attachChild(node1); + vehicleNode.attachChild(node2); + vehicleNode.attachChild(node3); + vehicleNode.attachChild(node4); + + rootNode.attachChild(vehicleNode); + getPhysicsSpace().add(vehicle); + + //driver + Node driverNode=new Node("driverNode"); + driverNode.setLocalTranslation(0,2,0); + driver=new RigidBodyControl(new BoxCollisionShape(new Vector3f(0.2f,.5f,0.2f))); + driverNode.addControl(driver); + + rootNode.attachChild(driverNode); + getPhysicsSpace().add(driver); + + //joint + slider=new SliderJoint(driver, vehicle, Vector3f.UNIT_Y.negate(), Vector3f.UNIT_Y, true); + slider.setUpperLinLimit(.1f); + slider.setLowerLinLimit(-.1f); + + getPhysicsSpace().add(slider); + + Node pole1Node=new Node("pole1Node"); + Node pole2Node=new Node("pole1Node"); + Node bridgeNode=new Node("pole1Node"); + pole1Node.setLocalTranslation(new Vector3f(-2,-1,4)); + pole2Node.setLocalTranslation(new Vector3f(2,-1,4)); + bridgeNode.setLocalTranslation(new Vector3f(0,1.4f,4)); + + RigidBodyControl pole1=new RigidBodyControl(new BoxCollisionShape(new Vector3f(0.2f,1.25f,0.2f)),0); + pole1Node.addControl(pole1); + RigidBodyControl pole2=new RigidBodyControl(new BoxCollisionShape(new Vector3f(0.2f,1.25f,0.2f)),0); + pole2Node.addControl(pole2); + bridge=new RigidBodyControl(new BoxCollisionShape(new Vector3f(2.5f,0.2f,0.2f))); + bridgeNode.addControl(bridge); + + rootNode.attachChild(pole1Node); + rootNode.attachChild(pole2Node); + rootNode.attachChild(bridgeNode); + getPhysicsSpace().add(pole1); + getPhysicsSpace().add(pole2); + getPhysicsSpace().add(bridge); + + } + + @Override + public void simpleUpdate(float tpf) { + Quaternion quat=new Quaternion(); + cam.lookAt(vehicle.getPhysicsLocation(), Vector3f.UNIT_Y); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Lefts")) { + if (value) { + steeringValue += .5f; + } else { + steeringValue += -.5f; + } + vehicle.steer(steeringValue); + } else if (binding.equals("Rights")) { + if (value) { + steeringValue += -.5f; + } else { + steeringValue += .5f; + } + vehicle.steer(steeringValue); + } else if (binding.equals("Ups")) { + if (value) { + accelerationValue += accelerationForce; + } else { + accelerationValue -= accelerationForce; + } + vehicle.accelerate(accelerationValue); + } else if (binding.equals("Downs")) { + if (value) { + vehicle.brake(brakeForce); + } else { + vehicle.brake(0f); + } + } else if (binding.equals("Space")) { + if (value) { + getPhysicsSpace().remove(slider); + slider.destroy(); + vehicle.applyImpulse(jumpForce, Vector3f.ZERO); + } + } else if (binding.equals("Reset")) { + if (value) { + System.out.println("Reset"); + vehicle.setPhysicsLocation(new Vector3f(0, 0, 0)); + vehicle.setPhysicsRotation(new Matrix3f()); + vehicle.setLinearVelocity(Vector3f.ZERO); + vehicle.setAngularVelocity(Vector3f.ZERO); + vehicle.resetSuspension(); + bridge.setPhysicsLocation(new Vector3f(0,1.4f,4)); + bridge.setPhysicsRotation(Quaternion.DIRECTION_Z.toRotationMatrix()); + } + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestAttachGhostObject.java b/JmeTests/src/jme3test/bullet/TestAttachGhostObject.java new file mode 100644 index 0000000..5fac3fc --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestAttachGhostObject.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.GhostControl; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.joints.HingeJoint; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +/** + * Tests attaching ghost nodes to physicsnodes via the scenegraph + * @author normenhansen + */ +public class TestAttachGhostObject extends SimpleApplication implements AnalogListener { + + private HingeJoint joint; + private GhostControl ghostControl; + private Node collisionNode; + private Node hammerNode; + private Vector3f tempVec = new Vector3f(); + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestAttachGhostObject app = new TestAttachGhostObject(); + app.start(); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, "Lefts", "Rights", "Space"); + } + + public void onAnalog(String binding, float value, float tpf) { + if (binding.equals("Lefts")) { + joint.enableMotor(true, 1, .1f); + } else if (binding.equals("Rights")) { + joint.enableMotor(true, -1, .1f); + } else if (binding.equals("Space")) { + joint.enableMotor(false, 0, 0); + } + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + setupKeys(); + setupJoint(); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + public void setupJoint() { + Node holderNode = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(.1f, .1f, .1f)), 0); + holderNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, 0, 0f)); + rootNode.attachChild(holderNode); + getPhysicsSpace().add(holderNode); + + Node hammerNode = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(.3f, .3f, .3f)), 1); + hammerNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -1, 0f)); + rootNode.attachChild(hammerNode); + getPhysicsSpace().add(hammerNode); + + //immovable + collisionNode = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(.3f, .3f, .3f)), 0); + collisionNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(1.8f, 0, 0f)); + rootNode.attachChild(collisionNode); + getPhysicsSpace().add(collisionNode); + + //ghost node + ghostControl = new GhostControl(new SphereCollisionShape(0.7f)); + + hammerNode.addControl(ghostControl); + getPhysicsSpace().add(ghostControl); + + joint = new HingeJoint(holderNode.getControl(RigidBodyControl.class), hammerNode.getControl(RigidBodyControl.class), Vector3f.ZERO, new Vector3f(0f, -1, 0f), Vector3f.UNIT_Z, Vector3f.UNIT_Z); + getPhysicsSpace().add(joint); + } + + @Override + public void simpleUpdate(float tpf) { + if (ghostControl.getOverlappingObjects().contains(collisionNode.getControl(PhysicsControl.class))) { + fpsText.setText("collide"); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestBetterCharacter.java b/JmeTests/src/jme3test/bullet/TestBetterCharacter.java new file mode 100644 index 0000000..e898a53 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestBetterCharacter.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.control.BetterCharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.CameraControl.ControlDirection; +import com.jme3.scene.shape.Sphere; +import com.jme3.system.AppSettings; + +/** + * A walking physical character followed by a 3rd person camera. (No animation.) + * + * @author normenhansen, zathras + */ +public class TestBetterCharacter extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState; + private BetterCharacterControl physicsCharacter; + private Node characterNode; + private CameraNode camNode; + boolean rotate = false; + private Vector3f walkDirection = new Vector3f(0, 0, 0); + private Vector3f viewDirection = new Vector3f(0, 0, 1); + boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, + leftRotate = false, rightRotate = false; + private Vector3f normalGravity = new Vector3f(0, -9.81f, 0); + private Geometry planet; + + public static void main(String[] args) { + TestBetterCharacter app = new TestBetterCharacter(); + AppSettings settings = new AppSettings(true); + settings.setRenderer(AppSettings.LWJGL_OPENGL2); + settings.setAudioRenderer(AppSettings.LWJGL_OPENAL); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + //setup keyboard mapping + setupKeys(); + + // activate physics + bulletAppState = new BulletAppState() { + @Override + public void prePhysicsTick(PhysicsSpace space, float tpf) { + // Apply radial gravity near the planet, downward gravity elsewhere. + checkPlanetGravity(); + } + }; + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + // init a physics test scene + PhysicsTestHelper.createPhysicsTestWorldSoccer(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + PhysicsTestHelper.createBallShooter(this, rootNode, bulletAppState.getPhysicsSpace()); + setupPlanet(); + + // Create a node for the character model + characterNode = new Node("character node"); + characterNode.setLocalTranslation(new Vector3f(4, 5, 2)); + + // Add a character control to the node so we can add other things and + // control the model rotation + physicsCharacter = new BetterCharacterControl(0.3f, 2.5f, 8f); + characterNode.addControl(physicsCharacter); + getPhysicsSpace().add(physicsCharacter); + + // Load model, attach to character node + Node model = (Node) assetManager.loadModel("Models/Jaime/Jaime.j3o"); + model.setLocalScale(1.50f); + characterNode.attachChild(model); + + // Add character node to the rootNode + rootNode.attachChild(characterNode); + + // Set forward camera node that follows the character, only used when + // view is "locked" + camNode = new CameraNode("CamNode", cam); + camNode.setControlDir(ControlDirection.SpatialToCamera); + camNode.setLocalTranslation(new Vector3f(0, 2, -6)); + Quaternion quat = new Quaternion(); + // These coordinates are local, the camNode is attached to the character node! + quat.lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y); + camNode.setLocalRotation(quat); + characterNode.attachChild(camNode); + // Disable by default, can be enabled via keyboard shortcut + camNode.setEnabled(false); + } + + @Override + public void simpleUpdate(float tpf) { + // Get current forward and left vectors of model by using its rotation + // to rotate the unit vectors + Vector3f modelForwardDir = characterNode.getWorldRotation().mult(Vector3f.UNIT_Z); + Vector3f modelLeftDir = characterNode.getWorldRotation().mult(Vector3f.UNIT_X); + + // WalkDirection is global! + // You *can* make your character fly with this. + walkDirection.set(0, 0, 0); + if (leftStrafe) { + walkDirection.addLocal(modelLeftDir.mult(3)); + } else if (rightStrafe) { + walkDirection.addLocal(modelLeftDir.negate().multLocal(3)); + } + if (forward) { + walkDirection.addLocal(modelForwardDir.mult(3)); + } else if (backward) { + walkDirection.addLocal(modelForwardDir.negate().multLocal(3)); + } + physicsCharacter.setWalkDirection(walkDirection); + + // ViewDirection is local to characters physics system! + // The final world rotation depends on the gravity and on the state of + // setApplyPhysicsLocal() + if (leftRotate) { + Quaternion rotateL = new Quaternion().fromAngleAxis(FastMath.PI * tpf, Vector3f.UNIT_Y); + rotateL.multLocal(viewDirection); + } else if (rightRotate) { + Quaternion rotateR = new Quaternion().fromAngleAxis(-FastMath.PI * tpf, Vector3f.UNIT_Y); + rotateR.multLocal(viewDirection); + } + physicsCharacter.setViewDirection(viewDirection); + fpsText.setText("Touch da ground = " + physicsCharacter.isOnGround()); + if (!lockView) { + cam.lookAt(characterNode.getWorldTranslation().add(new Vector3f(0, 2, 0)), Vector3f.UNIT_Y); + } + } + + private void setupPlanet() { + Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + //immovable sphere with mesh collision shape + Sphere sphere = new Sphere(64, 64, 20); + planet = new Geometry("Sphere", sphere); + planet.setMaterial(material); + planet.setLocalTranslation(30, -15, 30); + planet.addControl(new RigidBodyControl(new MeshCollisionShape(sphere), 0)); + rootNode.attachChild(planet); + getPhysicsSpace().add(planet); + } + + private void checkPlanetGravity() { + Vector3f planetDist = planet.getWorldTranslation().subtract(characterNode.getWorldTranslation()); + if (planetDist.length() < 24) { + physicsCharacter.setGravity(planetDist.normalizeLocal().multLocal(9.81f)); + } else { + physicsCharacter.setGravity(normalGravity); + } + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Strafe Left")) { + if (value) { + leftStrafe = true; + } else { + leftStrafe = false; + } + } else if (binding.equals("Strafe Right")) { + if (value) { + rightStrafe = true; + } else { + rightStrafe = false; + } + } else if (binding.equals("Rotate Left")) { + if (value) { + leftRotate = true; + } else { + leftRotate = false; + } + } else if (binding.equals("Rotate Right")) { + if (value) { + rightRotate = true; + } else { + rightRotate = false; + } + } else if (binding.equals("Walk Forward")) { + if (value) { + forward = true; + } else { + forward = false; + } + } else if (binding.equals("Walk Backward")) { + if (value) { + backward = true; + } else { + backward = false; + } + } else if (binding.equals("Jump")) { + physicsCharacter.jump(); + } else if (binding.equals("Duck")) { + if (value) { + physicsCharacter.setDucked(true); + } else { + physicsCharacter.setDucked(false); + } + } else if (binding.equals("Lock View")) { + if (value && lockView) { + lockView = false; + } else if (value && !lockView) { + lockView = true; + } + flyCam.setEnabled(!lockView); + camNode.setEnabled(lockView); + } + } + private boolean lockView = false; + + private void setupKeys() { + inputManager.addMapping("Strafe Left", + new KeyTrigger(KeyInput.KEY_U), + new KeyTrigger(KeyInput.KEY_Z)); + inputManager.addMapping("Strafe Right", + new KeyTrigger(KeyInput.KEY_O), + new KeyTrigger(KeyInput.KEY_X)); + inputManager.addMapping("Rotate Left", + new KeyTrigger(KeyInput.KEY_J), + new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Rotate Right", + new KeyTrigger(KeyInput.KEY_L), + new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("Walk Forward", + new KeyTrigger(KeyInput.KEY_I), + new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("Walk Backward", + new KeyTrigger(KeyInput.KEY_K), + new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("Jump", + new KeyTrigger(KeyInput.KEY_F), + new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Duck", + new KeyTrigger(KeyInput.KEY_G), + new KeyTrigger(KeyInput.KEY_LSHIFT), + new KeyTrigger(KeyInput.KEY_RSHIFT)); + inputManager.addMapping("Lock View", + new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Strafe Left", "Strafe Right"); + inputManager.addListener(this, "Rotate Left", "Rotate Right"); + inputManager.addListener(this, "Walk Forward", "Walk Backward"); + inputManager.addListener(this, "Jump", "Duck", "Lock View"); + } + + @Override + public void simpleRender(RenderManager rm) { + } +} diff --git a/JmeTests/src/jme3test/bullet/TestBoneRagdoll.java b/JmeTests/src/jme3test/bullet/TestBoneRagdoll.java new file mode 100644 index 0000000..bc806b0 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestBoneRagdoll.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.animation.*; +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionEvent; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.RagdollCollisionListener; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.KinematicRagdollControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.debug.SkeletonDebugger; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.texture.Texture; + +/** + * PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET! + * @author normenhansen + */ +public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener, AnimEventListener { + + private BulletAppState bulletAppState; + Material matBullet; + Node model; + KinematicRagdollControl ragdoll; + float bulletSize = 1f; + Material mat; + Material mat3; + private Sphere bullet; + private SphereCollisionShape bulletCollisionShape; + + public static void main(String[] args) { + TestBoneRagdoll app = new TestBoneRagdoll(); + app.start(); + } + + public void simpleInitApp() { + initCrossHairs(); + initMaterial(); + + cam.setLocation(new Vector3f(0.26924422f, 6.646658f, 22.265987f)); + cam.setRotation(new Quaternion(-2.302544E-4f, 0.99302495f, -0.117888905f, -0.0019395084f)); + + + bulletAppState = new BulletAppState(); + bulletAppState.setEnabled(true); + stateManager.attach(bulletAppState); + bullet = new Sphere(32, 32, 1.0f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(1.0f); + +// bulletAppState.getPhysicsSpace().enableDebug(assetManager); + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + setupLight(); + + model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + + // model.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X)); + + //debug view + AnimControl control = model.getControl(AnimControl.class); + SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton", control.getSkeleton()); + Material mat2 = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.getAdditionalRenderState().setWireframe(true); + mat2.setColor("Color", ColorRGBA.Green); + mat2.getAdditionalRenderState().setDepthTest(false); + skeletonDebug.setMaterial(mat2); + skeletonDebug.setLocalTranslation(model.getLocalTranslation()); + + //Note: PhysicsRagdollControl is still TODO, constructor will change + ragdoll = new KinematicRagdollControl(0.5f); + setupSinbad(ragdoll); + ragdoll.addCollisionListener(this); + model.addControl(ragdoll); + + float eighth_pi = FastMath.PI * 0.125f; + ragdoll.setJointLimit("Waist", eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi, eighth_pi); + ragdoll.setJointLimit("Chest", eighth_pi, eighth_pi, 0, 0, eighth_pi, eighth_pi); + + + //Oto's head is almost rigid + // ragdoll.setJointLimit("head", 0, 0, eighth_pi, -eighth_pi, 0, 0); + + getPhysicsSpace().add(ragdoll); + speed = 1.3f; + + rootNode.attachChild(model); + // rootNode.attachChild(skeletonDebug); + flyCam.setMoveSpeed(50); + + + animChannel = control.createChannel(); + animChannel.setAnim("Dance"); + control.addListener(this); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggle") && isPressed) { + + Vector3f v = new Vector3f(); + v.set(model.getLocalTranslation()); + v.y = 0; + model.setLocalTranslation(v); + Quaternion q = new Quaternion(); + float[] angles = new float[3]; + model.getLocalRotation().toAngles(angles); + q.fromAngleAxis(angles[1], Vector3f.UNIT_Y); + model.setLocalRotation(q); + if (angles[0] < 0) { + animChannel.setAnim("StandUpBack"); + ragdoll.blendToKinematicMode(0.5f); + } else { + animChannel.setAnim("StandUpFront"); + ragdoll.blendToKinematicMode(0.5f); + } + + } + if (name.equals("bullet+") && isPressed) { + bulletSize += 0.1f; + + } + if (name.equals("bullet-") && isPressed) { + bulletSize -= 0.1f; + + } + + if (name.equals("stop") && isPressed) { + ragdoll.setEnabled(!ragdoll.isEnabled()); + ragdoll.setRagdollMode(); + } + + if (name.equals("shoot") && !isPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(matBullet); + bulletg.setLocalTranslation(cam.getLocation()); + bulletg.setLocalScale(bulletSize); + bulletCollisionShape = new SphereCollisionShape(bulletSize); + RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, bulletSize * 10); + bulletNode.setCcdMotionThreshold(0.001f); + bulletNode.setLinearVelocity(cam.getDirection().mult(80)); + bulletg.addControl(bulletNode); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletNode); + } + if (name.equals("boom") && !isPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(matBullet); + bulletg.setLocalTranslation(cam.getLocation()); + bulletg.setLocalScale(bulletSize); + bulletCollisionShape = new SphereCollisionShape(bulletSize); + BombControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); + bulletNode.setForceFactor(8); + bulletNode.setExplosionRadius(20); + bulletNode.setCcdMotionThreshold(0.001f); + bulletNode.setLinearVelocity(cam.getDirection().mult(180)); + bulletg.addControl(bulletNode); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletNode); + } + } + }, "toggle", "shoot", "stop", "bullet+", "bullet-", "boom"); + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addMapping("boom", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("bullet-", new KeyTrigger(KeyInput.KEY_COMMA)); + inputManager.addMapping("bullet+", new KeyTrigger(KeyInput.KEY_PERIOD)); + + + } + + private void setupLight() { + // AmbientLight al = new AmbientLight(); + // al.setColor(ColorRGBA.White.mult(1)); + // rootNode.addLight(al); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + public void initMaterial() { + + matBullet = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = assetManager.loadTexture(key2); + matBullet.setTexture("ColorMap", tex2); + } + + protected void initCrossHairs() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2, + settings.getHeight() / 2 + ch.getLineHeight() / 2, 0); + guiNode.attachChild(ch); + } + + public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event) { + + if (object.getUserObject() != null && object.getUserObject() instanceof Geometry) { + Geometry geom = (Geometry) object.getUserObject(); + if ("Floor".equals(geom.getName())) { + return; + } + } + + ragdoll.setRagdollMode(); + + } + + private void setupSinbad(KinematicRagdollControl ragdoll) { + ragdoll.addBoneName("Ulna.L"); + ragdoll.addBoneName("Ulna.R"); + ragdoll.addBoneName("Chest"); + ragdoll.addBoneName("Foot.L"); + ragdoll.addBoneName("Foot.R"); + ragdoll.addBoneName("Hand.R"); + ragdoll.addBoneName("Hand.L"); + ragdoll.addBoneName("Neck"); + ragdoll.addBoneName("Root"); + ragdoll.addBoneName("Stomach"); + ragdoll.addBoneName("Waist"); + ragdoll.addBoneName("Humerus.L"); + ragdoll.addBoneName("Humerus.R"); + ragdoll.addBoneName("Thigh.L"); + ragdoll.addBoneName("Thigh.R"); + ragdoll.addBoneName("Calf.L"); + ragdoll.addBoneName("Calf.R"); + ragdoll.addBoneName("Clavicle.L"); + ragdoll.addBoneName("Clavicle.R"); + + } + float elTime = 0; + boolean forward = true; + AnimControl animControl; + AnimChannel animChannel; + Vector3f direction = new Vector3f(0, 0, 1); + Quaternion rotate = new Quaternion().fromAngleAxis(FastMath.PI / 8, Vector3f.UNIT_Y); + boolean dance = true; + + @Override + public void simpleUpdate(float tpf) { + // System.out.println(((BoundingBox) model.getWorldBound()).getYExtent()); +// elTime += tpf; +// if (elTime > 3) { +// elTime = 0; +// if (dance) { +// rotate.multLocal(direction); +// } +// if (Math.random() > 0.80) { +// dance = true; +// animChannel.setAnim("Dance"); +// } else { +// dance = false; +// animChannel.setAnim("RunBase"); +// rotate.fromAngleAxis(FastMath.QUARTER_PI * ((float) Math.random() - 0.5f), Vector3f.UNIT_Y); +// rotate.multLocal(direction); +// } +// } +// if (!ragdoll.hasControl() && !dance) { +// if (model.getLocalTranslation().getZ() < -10) { +// direction.z = 1; +// direction.normalizeLocal(); +// } else if (model.getLocalTranslation().getZ() > 10) { +// direction.z = -1; +// direction.normalizeLocal(); +// } +// if (model.getLocalTranslation().getX() < -10) { +// direction.x = 1; +// direction.normalizeLocal(); +// } else if (model.getLocalTranslation().getX() > 10) { +// direction.x = -1; +// direction.normalizeLocal(); +// } +// model.move(direction.multLocal(tpf * 8)); +// direction.normalizeLocal(); +// model.lookAt(model.getLocalTranslation().add(direction), Vector3f.UNIT_Y); +// } + } + + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { +// if(channel.getAnimationName().equals("StandUpFront")){ +// channel.setAnim("Dance"); +// } + + if (channel.getAnimationName().equals("StandUpBack") || channel.getAnimationName().equals("StandUpFront")) { + channel.setLoopMode(LoopMode.DontLoop); + channel.setAnim("IdleTop", 5); + channel.setLoopMode(LoopMode.Loop); + } +// if(channel.getAnimationName().equals("IdleTop")){ +// channel.setAnim("StandUpFront"); +// } + + } + + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } +} diff --git a/JmeTests/src/jme3test/bullet/TestBrickTower.java b/JmeTests/src/jme3test/bullet/TestBrickTower.java new file mode 100644 index 0000000..feffac8 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestBrickTower.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + +/** + * + * @author double1984 (tower mod by atom) + */ +public class TestBrickTower extends SimpleApplication { + + int bricksPerLayer = 8; + int brickLayers = 30; + + static float brickWidth = .75f, brickHeight = .25f, brickDepth = .25f; + float radius = 3f; + float angle = 0; + + + Material mat; + Material mat2; + Material mat3; + private Sphere bullet; + private Box brick; + private SphereCollisionShape bulletCollisionShape; + + private BulletAppState bulletAppState; + + public static void main(String args[]) { + TestBrickTower f = new TestBrickTower(); + f.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + // bulletAppState.setEnabled(false); + stateManager.attach(bulletAppState); + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.4f); + + brick = new Box(brickWidth, brickHeight, brickDepth); + brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); + initMaterial(); + initTower(); + initFloor(); + initCrossHairs(); + this.cam.setLocation(new Vector3f(0, 25f, 8f)); + cam.lookAt(Vector3f.ZERO, new Vector3f(0, 1, 0)); + cam.setFrustumFar(80); + inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "shoot"); + rootNode.setShadowMode(ShadowMode.Off); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("shoot") && !keyPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat2); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.setLocalTranslation(cam.getLocation()); + RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); +// RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, 1); + bulletNode.setLinearVelocity(cam.getDirection().mult(25)); + bulletg.addControl(bulletNode); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletNode); + } + } + }; + + public void initTower() { + double tempX = 0; + double tempY = 0; + double tempZ = 0; + angle = 0f; + for (int i = 0; i < brickLayers; i++){ + // Increment rows + if(i!=0) + tempY+=brickHeight*2; + else + tempY=brickHeight; + // Alternate brick seams + angle = 360.0f / bricksPerLayer * i/2f; + for (int j = 0; j < bricksPerLayer; j++){ + tempZ = Math.cos(Math.toRadians(angle))*radius; + tempX = Math.sin(Math.toRadians(angle))*radius; + System.out.println("x="+((float)(tempX))+" y="+((float)(tempY))+" z="+(float)(tempZ)); + Vector3f vt = new Vector3f((float)(tempX), (float)(tempY), (float)(tempZ)); + // Add crenelation + if (i==brickLayers-1){ + if (j%2 == 0){ + addBrick(vt); + } + } + // Create main tower + else { + addBrick(vt); + } + angle += 360.0/bricksPerLayer; + } + } + + } + + public void initFloor() { + Box floorBox = new Box(10f, 0.1f, 5f); + floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); + + Geometry floor = new Geometry("floor", floorBox); + floor.setMaterial(mat3); + floor.setShadowMode(ShadowMode.Receive); + floor.setLocalTranslation(0, 0, 0); + floor.addControl(new RigidBodyControl(0)); + this.rootNode.attachChild(floor); + this.getPhysicsSpace().add(floor); + } + + public void initMaterial() { + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + mat.setTexture("ColorMap", tex); + + mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = assetManager.loadTexture(key2); + mat2.setTexture("ColorMap", tex2); + + mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); + key3.setGenerateMips(true); + Texture tex3 = assetManager.loadTexture(key3); + tex3.setWrap(WrapMode.Repeat); + mat3.setTexture("ColorMap", tex3); + } + + public void addBrick(Vector3f ori) { + Geometry reBoxg = new Geometry("brick", brick); + reBoxg.setMaterial(mat); + reBoxg.setLocalTranslation(ori); + reBoxg.rotate(0f, (float)Math.toRadians(angle) , 0f ); + reBoxg.addControl(new RigidBodyControl(1.5f)); + reBoxg.setShadowMode(ShadowMode.CastAndReceive); + reBoxg.getControl(RigidBodyControl.class).setFriction(1.6f); + this.rootNode.attachChild(reBoxg); + this.getPhysicsSpace().add(reBoxg); + } + + protected void initCrossHairs() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2, + settings.getHeight() / 2 + ch.getLineHeight() / 2, 0); + guiNode.attachChild(ch); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/bullet/TestBrickWall.java b/JmeTests/src/jme3test/bullet/TestBrickWall.java new file mode 100644 index 0000000..b06d98f --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestBrickWall.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + +/** + * + * @author double1984 + */ +public class TestBrickWall extends SimpleApplication { + + static float bLength = 0.48f; + static float bWidth = 0.24f; + static float bHeight = 0.12f; + Material mat; + Material mat2; + Material mat3; + private static Sphere bullet; + private static Box brick; + private static SphereCollisionShape bulletCollisionShape; + + private BulletAppState bulletAppState; + + public static void main(String args[]) { + TestBrickWall f = new TestBrickWall(); + f.start(); + } + + @Override + public void simpleInitApp() { + + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + stateManager.attach(bulletAppState); + + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.4f); + brick = new Box(bLength, bHeight, bWidth); + brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); + + initMaterial(); + initWall(); + initFloor(); + initCrossHairs(); + this.cam.setLocation(new Vector3f(0, 6f, 6f)); + cam.lookAt(Vector3f.ZERO, new Vector3f(0, 1, 0)); + cam.setFrustumFar(15); + inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "shoot"); + inputManager.addMapping("gc", new KeyTrigger(KeyInput.KEY_X)); + inputManager.addListener(actionListener, "gc"); + + rootNode.setShadowMode(ShadowMode.Off); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("shoot") && !keyPressed) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat2); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.setLocalTranslation(cam.getLocation()); + + SphereCollisionShape bulletCollisionShape = new SphereCollisionShape(0.4f); + RigidBodyControl bulletNode = new BombControl(assetManager, bulletCollisionShape, 1); +// RigidBodyControl bulletNode = new RigidBodyControl(bulletCollisionShape, 1); + bulletNode.setLinearVelocity(cam.getDirection().mult(25)); + bulletg.addControl(bulletNode); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletNode); + } + if (name.equals("gc") && !keyPressed) { + System.gc(); + } + } + }; + + public void initWall() { + float startpt = bLength / 4; + float height = 0; + for (int j = 0; j < 15; j++) { + for (int i = 0; i < 4; i++) { + Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, 0); + addBrick(vt); + } + startpt = -startpt; + height += 2 * bHeight; + } + } + + public void initFloor() { + Box floorBox = new Box(10f, 0.1f, 5f); + floorBox.scaleTextureCoordinates(new Vector2f(3, 6)); + + Geometry floor = new Geometry("floor", floorBox); + floor.setMaterial(mat3); + floor.setShadowMode(ShadowMode.Receive); + floor.setLocalTranslation(0, -0.1f, 0); + floor.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(10f, 0.1f, 5f)), 0)); + this.rootNode.attachChild(floor); + this.getPhysicsSpace().add(floor); + } + + public void initMaterial() { + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + mat.setTexture("ColorMap", tex); + + mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = assetManager.loadTexture(key2); + mat2.setTexture("ColorMap", tex2); + + mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); + key3.setGenerateMips(true); + Texture tex3 = assetManager.loadTexture(key3); + tex3.setWrap(WrapMode.Repeat); + mat3.setTexture("ColorMap", tex3); + } + + public void addBrick(Vector3f ori) { + + Geometry reBoxg = new Geometry("brick", brick); + reBoxg.setMaterial(mat); + reBoxg.setLocalTranslation(ori); + //for geometry with sphere mesh the physics system automatically uses a sphere collision shape + reBoxg.addControl(new RigidBodyControl(1.5f)); + reBoxg.setShadowMode(ShadowMode.CastAndReceive); + reBoxg.getControl(RigidBodyControl.class).setFriction(0.6f); + this.rootNode.attachChild(reBoxg); + this.getPhysicsSpace().add(reBoxg); + } + + protected void initCrossHairs() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2, + settings.getHeight() / 2 + ch.getLineHeight() / 2, 0); + guiNode.attachChild(ch); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestCcd.java b/JmeTests/src/jme3test/bullet/TestCcd.java new file mode 100644 index 0000000..58cb77c --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestCcd.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; + +/** + * + * @author normenhansen + */ +public class TestCcd extends SimpleApplication implements ActionListener { + + private Material mat; + private Material mat2; + private Sphere bullet; + private SphereCollisionShape bulletCollisionShape; + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestCcd app = new TestCcd(); + app.start(); + } + + private void setupKeys() { + inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addMapping("shoot2", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + inputManager.addListener(this, "shoot"); + inputManager.addListener(this, "shoot2"); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.1f); + setupKeys(); + + mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", ColorRGBA.Green); + + mat2 = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.getAdditionalRenderState().setWireframe(true); + mat2.setColor("Color", ColorRGBA.Red); + + // An obstacle mesh, does not move (mass=0) + Node node2 = new Node(); + node2.setName("mesh"); + node2.setLocalTranslation(new Vector3f(2.5f, 0, 0f)); + node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(4, 4, 0.1f)), 0)); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // The floor, does not move (mass=0) + Node node3 = new Node(); + node3.setLocalTranslation(new Vector3f(0f, -6, 0f)); + node3.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(100, 1, 100)), 0)); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("shoot") && !value) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat); + bulletg.setName("bullet"); + bulletg.setLocalTranslation(cam.getLocation()); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); + bulletg.getControl(RigidBodyControl.class).setCcdMotionThreshold(0.1f); + bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletg); + } else if (binding.equals("shoot2") && !value) { + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(mat2); + bulletg.setName("bullet"); + bulletg.setLocalTranslation(cam.getLocation()); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); + bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletg); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestCollisionGroups.java b/JmeTests/src/jme3test/bullet/TestCollisionGroups.java new file mode 100644 index 0000000..516345d --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestCollisionGroups.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; + +/** + * + * @author normenhansen + */ +public class TestCollisionGroups extends SimpleApplication { + + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestCollisionGroups app = new TestCollisionGroups(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + // Add a physics sphere to the world + Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0)); + rootNode.attachChild(physicsSphere); + getPhysicsSpace().add(physicsSphere); + + // Add a physics sphere to the world + Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0)); + physicsSphere2.getControl(RigidBodyControl.class).addCollideWithGroup(PhysicsCollisionObject.COLLISION_GROUP_02); + rootNode.attachChild(physicsSphere2); + getPhysicsSpace().add(physicsSphere2); + + // an obstacle mesh, does not move (mass=0) + Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0); + node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f)); + node2.getControl(RigidBodyControl.class).setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_02); + node2.getControl(RigidBodyControl.class).setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_02); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // the floor, does not move (mass=0) + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Box(100f, 0.2f, 100f)), 0); + node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } +} diff --git a/JmeTests/src/jme3test/bullet/TestCollisionListener.java b/JmeTests/src/jme3test/bullet/TestCollisionListener.java new file mode 100644 index 0000000..3c9450f --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestCollisionListener.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionEvent; +import com.jme3.bullet.collision.PhysicsCollisionListener; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; + +/** + * + * @author normenhansen + */ +public class TestCollisionListener extends SimpleApplication implements PhysicsCollisionListener { + + private BulletAppState bulletAppState; + private Sphere bullet; + private SphereCollisionShape bulletCollisionShape; + + public static void main(String[] args) { + TestCollisionListener app = new TestCollisionListener(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.4f); + + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + PhysicsTestHelper.createBallShooter(this, rootNode, bulletAppState.getPhysicsSpace()); + + // add ourselves as collision listener + getPhysicsSpace().addCollisionListener(this); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } + + public void collision(PhysicsCollisionEvent event) { + if ("Box".equals(event.getNodeA().getName()) || "Box".equals(event.getNodeB().getName())) { + if ("bullet".equals(event.getNodeA().getName()) || "bullet".equals(event.getNodeB().getName())) { + fpsText.setText("You hit the box!"); + } + } + } + +} diff --git a/JmeTests/src/jme3test/bullet/TestCollisionShapeFactory.java b/JmeTests/src/jme3test/bullet/TestCollisionShapeFactory.java new file mode 100644 index 0000000..2128149 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestCollisionShapeFactory.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Cylinder; +import com.jme3.scene.shape.Torus; + +/** + * This is a basic Test of jbullet-jme functions + * + * @author normenhansen + */ +public class TestCollisionShapeFactory extends SimpleApplication { + + private BulletAppState bulletAppState; + private Material mat1; + private Material mat2; + private Material mat3; + + public static void main(String[] args) { + TestCollisionShapeFactory app = new TestCollisionShapeFactory(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + createMaterial(); + + Node node = new Node("node1"); + attachRandomGeometry(node, mat1); + randomizeTransform(node); + + Node node2 = new Node("node2"); + attachRandomGeometry(node2, mat2); + randomizeTransform(node2); + + node.attachChild(node2); + rootNode.attachChild(node); + + RigidBodyControl control = new RigidBodyControl(0); + node.addControl(control); + getPhysicsSpace().add(control); + + //test single geometry too + Geometry myGeom = new Geometry("cylinder", new Cylinder(16, 16, 0.5f, 1)); + myGeom.setMaterial(mat3); + randomizeTransform(myGeom); + rootNode.attachChild(myGeom); + RigidBodyControl control3 = new RigidBodyControl(0); + myGeom.addControl(control3); + getPhysicsSpace().add(control3); + } + + private void attachRandomGeometry(Node node, Material mat) { + Box box = new Box(0.25f, 0.25f, 0.25f); + Torus torus = new Torus(16, 16, 0.2f, 0.8f); + Geometry[] boxes = new Geometry[]{ + new Geometry("box1", box), + new Geometry("box2", box), + new Geometry("box3", box), + new Geometry("torus1", torus), + new Geometry("torus2", torus), + new Geometry("torus3", torus) + }; + for (int i = 0; i < boxes.length; i++) { + Geometry geometry = boxes[i]; + geometry.setLocalTranslation((float) Math.random() * 10 -10, (float) Math.random() * 10 -10, (float) Math.random() * 10 -10); + geometry.setLocalRotation(new Quaternion().fromAngles((float) Math.random() * FastMath.PI, (float) Math.random() * FastMath.PI, (float) Math.random() * FastMath.PI)); + geometry.setLocalScale((float) Math.random() * 10 -10, (float) Math.random() * 10 -10, (float) Math.random() * 10 -10); + geometry.setMaterial(mat); + node.attachChild(geometry); + } + } + + private void randomizeTransform(Spatial spat){ + spat.setLocalTranslation((float) Math.random() * 10, (float) Math.random() * 10, (float) Math.random() * 10); + spat.setLocalTranslation((float) Math.random() * 10, (float) Math.random() * 10, (float) Math.random() * 10); + spat.setLocalScale((float) Math.random() * 2, (float) Math.random() * 2, (float) Math.random() * 2); + } + + private void createMaterial() { + mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Green); + mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setColor("Color", ColorRGBA.Red); + mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat3.setColor("Color", ColorRGBA.Yellow); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestFancyCar.java b/JmeTests/src/jme3test/bullet/TestFancyCar.java new file mode 100644 index 0000000..3803c4c --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestFancyCar.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.bullet.util.CollisionShapeFactory; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.FastMath; +import com.jme3.math.Matrix3f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +public class TestFancyCar extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState; + private VehicleControl player; + private VehicleWheel fr, fl, br, bl; + private Node node_fr, node_fl, node_br, node_bl; + private float wheelRadius; + private float steeringValue = 0; + private float accelerationValue = 0; + private Node carNode; + + public static void main(String[] args) { + TestFancyCar app = new TestFancyCar(); + app.start(); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Lefts"); + inputManager.addListener(this, "Rights"); + inputManager.addListener(this, "Ups"); + inputManager.addListener(this, "Downs"); + inputManager.addListener(this, "Space"); + inputManager.addListener(this, "Reset"); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); +// bulletAppState.getPhysicsSpace().enableDebug(assetManager); + cam.setFrustumFar(150f); + flyCam.setMoveSpeed(10); + + setupKeys(); + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); +// setupFloor(); + buildPlayer(); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.5f, -1f, -0.3f).normalizeLocal()); + rootNode.addLight(dl); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(0.5f, -0.1f, 0.3f).normalizeLocal()); + // rootNode.addLight(dl); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + +// public void setupFloor() { +// Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); +// mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); +//// mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); +//// mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat); +// +// Box floor = new Box(Vector3f.ZERO, 140, 1f, 140); +// floor.scaleTextureCoordinates(new Vector2f(112.0f, 112.0f)); +// Geometry floorGeom = new Geometry("Floor", floor); +// floorGeom.setShadowMode(ShadowMode.Receive); +// floorGeom.setMaterial(mat); +// +// PhysicsNode tb = new PhysicsNode(floorGeom, new MeshCollisionShape(floorGeom.getMesh()), 0); +// tb.setLocalTranslation(new Vector3f(0f, -6, 0f)); +//// tb.attachDebugShape(assetManager); +// rootNode.attachChild(tb); +// getPhysicsSpace().add(tb); +// } + + private Geometry findGeom(Spatial spatial, String name) { + if (spatial instanceof Node) { + Node node = (Node) spatial; + for (int i = 0; i < node.getQuantity(); i++) { + Spatial child = node.getChild(i); + Geometry result = findGeom(child, name); + if (result != null) { + return result; + } + } + } else if (spatial instanceof Geometry) { + if (spatial.getName().startsWith(name)) { + return (Geometry) spatial; + } + } + return null; + } + + private void buildPlayer() { + float stiffness = 120.0f;//200=f1 car + float compValue = 0.2f; //(lower than damp!) + float dampValue = 0.3f; + final float mass = 400; + + //Load model and get chassis Geometry + carNode = (Node)assetManager.loadModel("Models/Ferrari/Car.scene"); + carNode.setShadowMode(ShadowMode.Cast); + Geometry chasis = findGeom(carNode, "Car"); + BoundingBox box = (BoundingBox) chasis.getModelBound(); + + //Create a hull collision shape for the chassis + CollisionShape carHull = CollisionShapeFactory.createDynamicMeshShape(chasis); + + //Create a vehicle control + player = new VehicleControl(carHull, mass); + carNode.addControl(player); + + //Setting default values for wheels + player.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness)); + player.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness)); + player.setSuspensionStiffness(stiffness); + player.setMaxSuspensionForce(10000); + + //Create four wheels and add them at their locations + //note that our fancy car actually goes backwards.. + Vector3f wheelDirection = new Vector3f(0, -1, 0); + Vector3f wheelAxle = new Vector3f(-1, 0, 0); + + Geometry wheel_fr = findGeom(carNode, "WheelFrontRight"); + wheel_fr.center(); + box = (BoundingBox) wheel_fr.getModelBound(); + wheelRadius = box.getYExtent(); + float back_wheel_h = (wheelRadius * 1.7f) - 1f; + float front_wheel_h = (wheelRadius * 1.9f) - 1f; + player.addWheel(wheel_fr.getParent(), box.getCenter().add(0, -front_wheel_h, 0), + wheelDirection, wheelAxle, 0.2f, wheelRadius, true); + + Geometry wheel_fl = findGeom(carNode, "WheelFrontLeft"); + wheel_fl.center(); + box = (BoundingBox) wheel_fl.getModelBound(); + player.addWheel(wheel_fl.getParent(), box.getCenter().add(0, -front_wheel_h, 0), + wheelDirection, wheelAxle, 0.2f, wheelRadius, true); + + Geometry wheel_br = findGeom(carNode, "WheelBackRight"); + wheel_br.center(); + box = (BoundingBox) wheel_br.getModelBound(); + player.addWheel(wheel_br.getParent(), box.getCenter().add(0, -back_wheel_h, 0), + wheelDirection, wheelAxle, 0.2f, wheelRadius, false); + + Geometry wheel_bl = findGeom(carNode, "WheelBackLeft"); + wheel_bl.center(); + box = (BoundingBox) wheel_bl.getModelBound(); + player.addWheel(wheel_bl.getParent(), box.getCenter().add(0, -back_wheel_h, 0), + wheelDirection, wheelAxle, 0.2f, wheelRadius, false); + + player.getWheel(2).setFrictionSlip(4); + player.getWheel(3).setFrictionSlip(4); + + rootNode.attachChild(carNode); + getPhysicsSpace().add(player); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Lefts")) { + if (value) { + steeringValue += .5f; + } else { + steeringValue += -.5f; + } + player.steer(steeringValue); + } else if (binding.equals("Rights")) { + if (value) { + steeringValue += -.5f; + } else { + steeringValue += .5f; + } + player.steer(steeringValue); + } //note that our fancy car actually goes backwards.. + else if (binding.equals("Ups")) { + if (value) { + accelerationValue -= 800; + } else { + accelerationValue += 800; + } + player.accelerate(accelerationValue); + player.setCollisionShape(CollisionShapeFactory.createDynamicMeshShape(findGeom(carNode, "Car"))); + } else if (binding.equals("Downs")) { + if (value) { + player.brake(40f); + } else { + player.brake(0f); + } + } else if (binding.equals("Reset")) { + if (value) { + System.out.println("Reset"); + player.setPhysicsLocation(Vector3f.ZERO); + player.setPhysicsRotation(new Matrix3f()); + player.setLinearVelocity(Vector3f.ZERO); + player.setAngularVelocity(Vector3f.ZERO); + player.resetSuspension(); + } else { + } + } + } + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(carNode.getWorldTranslation(), Vector3f.UNIT_Y); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestGhostObject.java b/JmeTests/src/jme3test/bullet/TestGhostObject.java new file mode 100644 index 0000000..2ea1af0 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestGhostObject.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.Application; +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.GhostControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; + +/** + * + * @author tim8dev [at] gmail [dot com] + */ +public class TestGhostObject extends SimpleApplication { + + private BulletAppState bulletAppState; + private GhostControl ghostControl; + + public static void main(String[] args) { + Application app = new TestGhostObject(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + // Mesh to be shared across several boxes. + Box boxGeom = new Box(1f, 1f, 1f); + // CollisionShape to be shared across several boxes. + CollisionShape shape = new BoxCollisionShape(new Vector3f(1, 1, 1)); + + Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, shape, 1); + physicsBox.setName("box0"); + physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f)); + rootNode.attachChild(physicsBox); + getPhysicsSpace().add(physicsBox); + + Node physicsBox1 = PhysicsTestHelper.createPhysicsTestNode(assetManager, shape, 1); + physicsBox1.setName("box1"); + physicsBox1.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0, 40, 0)); + rootNode.attachChild(physicsBox1); + getPhysicsSpace().add(physicsBox1); + + Node physicsBox2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1); + physicsBox2.setName("box0"); + physicsBox2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.5f, 80, -.8f)); + rootNode.attachChild(physicsBox2); + getPhysicsSpace().add(physicsBox2); + + // the floor, does not move (mass=0) + Node node = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(100, 1, 100)), 0); + node.setName("floor"); + node.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + rootNode.attachChild(node); + getPhysicsSpace().add(node); + + initGhostObject(); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + private void initGhostObject() { + Vector3f halfExtents = new Vector3f(3, 4.2f, 1); + ghostControl = new GhostControl(new BoxCollisionShape(halfExtents)); + Node node=new Node("Ghost Object"); + node.addControl(ghostControl); + rootNode.attachChild(node); + getPhysicsSpace().add(ghostControl); + } + + @Override + public void simpleUpdate(float tpf) { + fpsText.setText("Overlapping objects: " + ghostControl.getOverlappingObjects().toString()); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestHoveringTank.java b/JmeTests/src/jme3test/bullet/TestHoveringTank.java new file mode 100644 index 0000000..a241072 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestHoveringTank.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.util.CollisionShapeFactory; +import com.jme3.font.BitmapText; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.system.AppSettings; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import java.util.ArrayList; +import java.util.List; + +public class TestHoveringTank extends SimpleApplication implements AnalogListener, + ActionListener { + + private BulletAppState bulletAppState; + private PhysicsHoverControl hoverControl; + private Spatial spaceCraft; + TerrainQuad terrain; + Material matRock; + boolean wireframe = false; + protected BitmapText hintText; + PointLight pl; + Geometry lightMdl; + Geometry collisionMarker; + + public static void main(String[] args) { + TestHoveringTank app = new TestHoveringTank(); + app.start(); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Lefts"); + inputManager.addListener(this, "Rights"); + inputManager.addListener(this, "Ups"); + inputManager.addListener(this, "Downs"); + inputManager.addListener(this, "Space"); + inputManager.addListener(this, "Reset"); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + stateManager.attach(bulletAppState); +// bulletAppState.getPhysicsSpace().enableDebug(assetManager); + bulletAppState.getPhysicsSpace().setAccuracy(1f/30f); + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", EnvMapType.CubeMap)); + + DirectionalLightShadowRenderer dlsr + = new DirectionalLightShadowRenderer(assetManager, 2048, 3); + dlsr.setLambda(0.55f); + dlsr.setShadowIntensity(0.6f); + dlsr.setEdgeFilteringMode(EdgeFilteringMode.Bilinear); + viewPort.addProcessor(dlsr); + + setupKeys(); + createTerrain(); + buildPlayer(); + + DirectionalLight dl = new DirectionalLight(); + dlsr.setLight(dl); + dl.setColor(new ColorRGBA(1.0f, 0.94f, 0.8f, 1f).multLocal(1.3f)); + dl.setDirection(new Vector3f(-0.5f, -0.3f, -0.3f).normalizeLocal()); + rootNode.addLight(dl); + + Vector3f lightDir2 = new Vector3f(0.70518064f, 0.5902297f, -0.39287305f); + DirectionalLight dl2 = new DirectionalLight(); + dl2.setColor(new ColorRGBA(0.7f, 0.85f, 1.0f, 1f)); + dl2.setDirection(lightDir2); + rootNode.addLight(dl2); + } + + private void buildPlayer() { + spaceCraft = assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); + CollisionShape colShape = CollisionShapeFactory.createDynamicMeshShape(spaceCraft); + spaceCraft.setShadowMode(ShadowMode.CastAndReceive); + spaceCraft.setLocalTranslation(new Vector3f(-140, 50, -23)); + spaceCraft.setLocalRotation(new Quaternion(new float[]{0, 0.01f, 0})); + + hoverControl = new PhysicsHoverControl(colShape, 500); + + spaceCraft.addControl(hoverControl); + + + rootNode.attachChild(spaceCraft); + getPhysicsSpace().add(hoverControl); + hoverControl.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_02); + + ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); + spaceCraft.addControl(chaseCam); + + flyCam.setEnabled(false); + } + + public void makeMissile() { + Vector3f pos = spaceCraft.getWorldTranslation().clone(); + Quaternion rot = spaceCraft.getWorldRotation(); + Vector3f dir = rot.getRotationColumn(2); + + Spatial missile = assetManager.loadModel("Models/SpaceCraft/Rocket.mesh.xml"); + missile.scale(0.5f); + missile.rotate(0, FastMath.PI, 0); + missile.updateGeometricState(); + + BoundingBox box = (BoundingBox) missile.getWorldBound(); + final Vector3f extent = box.getExtent(null); + + BoxCollisionShape boxShape = new BoxCollisionShape(extent); + + missile.setName("Missile"); + missile.rotate(rot); + missile.setLocalTranslation(pos.addLocal(0, extent.y * 4.5f, 0)); + missile.setLocalRotation(hoverControl.getPhysicsRotation()); + missile.setShadowMode(ShadowMode.Cast); + RigidBodyControl control = new BombControl(assetManager, boxShape, 20); + control.setLinearVelocity(dir.mult(100)); + control.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_03); + missile.addControl(control); + + + rootNode.attachChild(missile); + getPhysicsSpace().add(missile); + } + + public void onAnalog(String binding, float value, float tpf) { + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Lefts")) { + hoverControl.steer(value ? 50f : 0); + } else if (binding.equals("Rights")) { + hoverControl.steer(value ? -50f : 0); + } else if (binding.equals("Ups")) { + hoverControl.accelerate(value ? 100f : 0); + } else if (binding.equals("Downs")) { + hoverControl.accelerate(value ? -100f : 0); + } else if (binding.equals("Reset")) { + if (value) { + System.out.println("Reset"); + hoverControl.setPhysicsLocation(new Vector3f(-140, 14, -23)); + hoverControl.setPhysicsRotation(new Matrix3f()); + hoverControl.clearForces(); + } else { + } + } else if (binding.equals("Space") && value) { + makeMissile(); + } + } + + public void updateCamera() { + rootNode.updateGeometricState(); + + Vector3f pos = spaceCraft.getWorldTranslation().clone(); + Quaternion rot = spaceCraft.getWorldRotation(); + Vector3f dir = rot.getRotationColumn(2); + + // make it XZ only + Vector3f camPos = new Vector3f(dir); + camPos.setY(0); + camPos.normalizeLocal(); + + // negate and multiply by distance from object + camPos.negateLocal(); + camPos.multLocal(15); + + // add Y distance + camPos.setY(2); + camPos.addLocal(pos); + cam.setLocation(camPos); + + Vector3f lookAt = new Vector3f(dir); + lookAt.multLocal(7); // look at dist + lookAt.addLocal(pos); + cam.lookAt(lookAt, Vector3f.UNIT_Y); + } + + @Override + public void simpleUpdate(float tpf) { + } + + private void createTerrain() { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + TerrainLodControl control = new TerrainLodControl(terrain, cameras); + terrain.addControl(control); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(2, 2, 2)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(ShadowMode.CastAndReceive); + terrain.addControl(new RigidBodyControl(0)); + rootNode.attachChild(terrain); + getPhysicsSpace().addAll(terrain); + + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIK.java b/JmeTests/src/jme3test/bullet/TestIK.java new file mode 100644 index 0000000..43313e7 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIK.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.Bone; +import com.jme3.bullet.collision.RagdollCollisionListener; +import com.jme3.bullet.control.KinematicRagdollControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +/** + * @author reden + */ +public class TestIK extends TestBoneRagdoll implements RagdollCollisionListener, AnimEventListener { + + Node targetNode = new Node(""); + Vector3f targetPoint; + Bone mouseBone; + Vector3f oldMousePos; + + public static void main(String[] args) { + TestIK app = new TestIK(); + app.start(); + } + + @Override + public void simpleInitApp() { + super.simpleInitApp(); + final KinematicRagdollControl ikControl = model.getControl(KinematicRagdollControl.class); + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + + if (name.equals("stop") && isPressed) { + ikControl.setEnabled(!ikControl.isEnabled()); + ikControl.setIKMode(); + } + + if (name.equals("one") && isPressed) { + //ragdoll.setKinematicMode(); + targetPoint = model.getWorldTranslation().add(new Vector3f(0,2,4)); + targetNode.setLocalTranslation(targetPoint); + ikControl.setIKTarget(ikControl.getBone("Hand.L"), targetPoint, 2); + ikControl.setIKMode(); + } + if (name.equals("two") && isPressed) { + //ragdoll.setKinematicMode(); + targetPoint = model.getWorldTranslation().add(new Vector3f(-3,3,0)); + targetNode.setLocalTranslation(targetPoint); + ikControl.setIKTarget(ikControl.getBone("Hand.R"), targetPoint, 3); + ikControl.setIKMode(); + } + } + }, "one", "two"); + inputManager.addMapping("one", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("two", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_H)); + } + +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue877.java b/JmeTests/src/jme3test/bullet/TestIssue877.java new file mode 100644 index 0000000..d17d340 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue877.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +/** + * Test case for JME issue #877: multiple hinges. Based on code submitted by + * Daniel Martensson. + * + * If successful, all pendulums will swing at the same frequency, and all the + * free-falling objects will fall straight down. + */ +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.joints.HingeJoint; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +public class TestIssue877 extends SimpleApplication { + + BulletAppState bulletAppState = new BulletAppState(); + int numPendulums = 6; + int numFalling = 6; + Node pivots[] = new Node[numPendulums]; + Node bobs[] = new Node[numPendulums]; + Node falling[] = new Node[numFalling]; + float timeToNextPrint = 1f; // in seconds + + public static void main(String[] args) { + TestIssue877 app = new TestIssue877(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + cam.setLocation(new Vector3f(-4.77f, -7.55f, 16.52f)); + cam.setRotation(new Quaternion(-0.103433f, 0.889420f, 0.368792f, 0.249449f)); + + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + float pivotY = 14.6214f; + float bobStartY = 3f; + float length = pivotY - bobStartY; + for (int i = 0; i < numPendulums; i++) { + float x = 6f - 2.5f * i; + Vector3f pivotLocation = new Vector3f(x, pivotY, 0f); + pivots[i] = createTestNode(0f, pivotLocation); + + Vector3f bobLocation = new Vector3f(x, bobStartY, 0f); + bobs[i] = createTestNode(1f, bobLocation); + } + + for (int i = 0; i < numFalling; i++) { + float x = -6f - 2.5f * (i + numPendulums); + Vector3f createLocation = new Vector3f(x, bobStartY, 0f); + falling[i] = createTestNode(1f, createLocation); + } + + for (int i = 0; i < numPendulums; i++) { + HingeJoint joint = new HingeJoint( + pivots[i].getControl(RigidBodyControl.class), + bobs[i].getControl(RigidBodyControl.class), + new Vector3f(0f, 0f, 0f), + new Vector3f(length, 0f, 0f), + Vector3f.UNIT_Z.clone(), + Vector3f.UNIT_Z.clone()); + bulletAppState.getPhysicsSpace().add(joint); + } + } + + Node createTestNode(float mass, Vector3f location) { + float size = 0.1f; + Vector3f halfExtents = new Vector3f(size, size, size); + CollisionShape shape = new BoxCollisionShape(halfExtents); + RigidBodyControl control = new RigidBodyControl(shape, mass); + Node node = new Node(); + node.addControl(control); + rootNode.attachChild(node); + bulletAppState.getPhysicsSpace().add(node); + control.setPhysicsLocation(location); + + return node; + } + + @Override + public void simpleUpdate(float tpf) { + if (timeToNextPrint > 0f) { + timeToNextPrint -= tpf; + return; + } + + if (numFalling > 0) { + Vector3f fallingLocation = falling[0].getWorldTranslation(); + System.out.printf(" falling[0] location(x=%f, z=%f)", + fallingLocation.x, fallingLocation.z); + /* + * If an object is falling vertically, its X- and Z-coordinates + * should not change. + */ + } + if (numPendulums > 0) { + Vector3f bobLocation = bobs[0].getWorldTranslation(); + Vector3f pivotLocation = pivots[0].getWorldTranslation(); + float distance = bobLocation.distance(pivotLocation); + System.out.printf(" bob[0] distance=%f", distance); + /* + * If the hinge is working properly, the distance from the + * pivot to the bob should remain roughly constant. + */ + } + System.out.println(); + timeToNextPrint = 1f; + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue883.java b/JmeTests/src/jme3test/bullet/TestIssue883.java new file mode 100644 index 0000000..f4e794f --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue883.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +/** + * Test case for JME issue #883: extra physicsTicks in ThreadingType.PARALLEL. + * + * If successful, physics time and frame time will advance at the same rate. + */ +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; + +public class TestIssue883 extends SimpleApplication { + + boolean firstPrint = true; + float timeToNextPrint = 1f; // in seconds + double frameTime; // in seconds + double physicsTime; // in seconds + + public static void main(String[] args) { + TestIssue883 app = new TestIssue883(); + app.start(); + } + + @Override + public void simpleInitApp() { + + BulletAppState bulletAppState = new BulletAppState() { + @Override + public void physicsTick(PhysicsSpace space, float timeStep) { + physicsTime += timeStep; + } + }; + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + stateManager.attach(bulletAppState); + } + + @Override + public void simpleUpdate(float tpf) { + frameTime += tpf; + + if (timeToNextPrint > 0f) { + timeToNextPrint -= tpf; + return; + } + + if (firstPrint) { // synchronize + frameTime = 0.; + physicsTime = 0.; + firstPrint = false; + } + + System.out.printf(" frameTime= %s physicsTime= %s%n", + frameTime, physicsTime); + timeToNextPrint = 1f; + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue889.java b/JmeTests/src/jme3test/bullet/TestIssue889.java new file mode 100644 index 0000000..0704233 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue889.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +/** + * Test case for JME issue #889: disabled physics control gets added to a + * physics space. + *

+ * If successful, no debug meshes will be visible. + */ +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.BetterCharacterControl; +import com.jme3.bullet.control.GhostControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Vector3f; + +public class TestIssue889 extends SimpleApplication { + + public static void main(String[] args) { + TestIssue889 app = new TestIssue889(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + + BulletAppState bulletAppState = new BulletAppState(); + bulletAppState.setDebugEnabled(true); + bulletAppState.setSpeed(0f); + stateManager.attach(bulletAppState); + PhysicsSpace space = bulletAppState.getPhysicsSpace(); + + float radius = 1f; + CollisionShape sphere = new SphereCollisionShape(radius); + CollisionShape box = new BoxCollisionShape(Vector3f.UNIT_XYZ); + + RigidBodyControl rbc = new RigidBodyControl(box); + rbc.setEnabled(false); + rbc.setPhysicsSpace(space); + rootNode.addControl(rbc); + + BetterCharacterControl bcc = new BetterCharacterControl(radius, 4f, 1f); + bcc.setEnabled(false); + bcc.setPhysicsSpace(space); + rootNode.addControl(bcc); + + GhostControl gc = new GhostControl(sphere); + gc.setEnabled(false); + gc.setPhysicsSpace(space); + rootNode.addControl(gc); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue918.java b/JmeTests/src/jme3test/bullet/TestIssue918.java new file mode 100644 index 0000000..ed5a726 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue918.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.joints.Point2PointJoint; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.math.Vector3f; + +/** + * Test case for JME issue #918: Point2PointJoint.getImpulseClamp() and + * .getTau() return the damping value instead. The bug existed in Native Bullet + * only. + *

+ * If successful, no UnsatisfiedLinkError exception will be thrown. + */ +public class TestIssue918 extends SimpleApplication { + // ************************************************************************* + // new methods exposed + + public static void main(String[] args) { + TestIssue918 app = new TestIssue918(); + app.start(); + } + // ************************************************************************* + // SimpleApplication methods + + @Override + public void simpleInitApp() { + CollisionShape capsule = new SphereCollisionShape(1f); + PhysicsRigidBody body1 = new PhysicsRigidBody(capsule, 1f); + PhysicsRigidBody body2 = new PhysicsRigidBody(capsule, 1f); + Vector3f pivot1 = new Vector3f(); + Vector3f pivot2 = new Vector3f(); + Point2PointJoint joint + = new Point2PointJoint(body1, body2, pivot1, pivot2); + + joint.setImpulseClamp(42f); + joint.setTau(99f); + + if (joint.getImpulseClamp() != 42f) { + throw new RuntimeException(); + } + if (joint.getTau() != 99f) { + throw new RuntimeException(); + } + + stop(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue919.java b/JmeTests/src/jme3test/bullet/TestIssue919.java new file mode 100644 index 0000000..3fb6578 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue919.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.joints.SixDofJoint; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.math.Vector3f; + +/** + * Test case for JME issue #919: native implementation of + * TranslationalLimitMotor.getLimitSoftness() has wrong name. The bug existed in + * Native Bullet only. + *

+ * If successful, no UnsatisfiedLinkError exception will be thrown. + */ +public class TestIssue919 extends SimpleApplication { + // ************************************************************************* + // new methods exposed + + public static void main(String[] args) { + TestIssue919 app = new TestIssue919(); + app.start(); + } + // ************************************************************************* + // SimpleApplication methods + + @Override + public void simpleInitApp() { + CollisionShape capsule = new SphereCollisionShape(1f); + PhysicsRigidBody body1 = new PhysicsRigidBody(capsule, 1f); + PhysicsRigidBody body2 = new PhysicsRigidBody(capsule, 1f); + Vector3f pivot1 = new Vector3f(); + Vector3f pivot2 = new Vector3f(); + SixDofJoint joint = new SixDofJoint(body1, body2, pivot1, pivot2, true); + + joint.getTranslationalLimitMotor().getLimitSoftness(); + + stop(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestIssue928.java b/JmeTests/src/jme3test/bullet/TestIssue928.java new file mode 100644 index 0000000..886fb82 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestIssue928.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.BulletAppState.ThreadingType; + +/** + * Test case for JME issue #928: crash after 64 attached and detached + * BulletAppStates with parallel threading. The bug existed in Native Bullet + * only. + *

+ * If successful, no crash will occur. + */ +public class TestIssue928 extends SimpleApplication { + // ************************************************************************* + // new methods exposed + + public static void main(String[] args) { + TestIssue928 app = new TestIssue928(); + app.start(); + } + + int count = 0; + int frame = 0; + BulletAppState bulletAppState; + // ************************************************************************* + // SimpleApplication methods + + @Override + public void simpleInitApp() { + } + + @Override + public void simpleUpdate(float tpf) { + if (frame % 4 == 0) { + System.out.println(++count); + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(ThreadingType.PARALLEL); + stateManager.attach(bulletAppState); + } else if (frame % 4 == 2) { + stateManager.detach(bulletAppState); + } + + frame++; + if (count == 70) { + System.exit(0); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java b/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java new file mode 100644 index 0000000..84bf607 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.collision.shapes.PlaneCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Plane; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; + +/** + * + * @author Nehon + */ +public class TestKinematicAddToPhysicsSpaceIssue extends SimpleApplication { + + public static void main(String[] args) { + TestKinematicAddToPhysicsSpaceIssue app = new TestKinematicAddToPhysicsSpaceIssue(); + app.start(); + } + BulletAppState bulletAppState; + + @Override + public void simpleInitApp() { + + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + // Add a physics sphere to the world + Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0)); + rootNode.attachChild(physicsSphere); + + //Setting the rigidBody to kinematic before adding it to the physics space + physicsSphere.getControl(RigidBodyControl.class).setKinematic(true); + //adding it to the physics space + getPhysicsSpace().add(physicsSphere); + //Making it not kinematic again, it should fall under gravity, it doesn't + physicsSphere.getControl(RigidBodyControl.class).setKinematic(false); + + // Add a physics sphere to the world using the collision shape from sphere one + Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(5, 6, 0)); + rootNode.attachChild(physicsSphere2); + + //Adding the rigid body to physics space + getPhysicsSpace().add(physicsSphere2); + //making it kinematic + physicsSphere2.getControl(RigidBodyControl.class).setKinematic(false); + //Making it not kinematic again, it works properly, the rigidbody is affected by grvity. + physicsSphere2.getControl(RigidBodyControl.class).setKinematic(false); + + + + // an obstacle mesh, does not move (mass=0) + Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0); + node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f)); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // the floor mesh, does not move (mass=0) + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0); + node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestLocalPhysics.java b/JmeTests/src/jme3test/bullet/TestLocalPhysics.java new file mode 100644 index 0000000..3835b1c --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestLocalPhysics.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.*; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Plane; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; + +/** + * This is a basic Test of jbullet-jme functions + * + * @author normenhansen + */ +public class TestLocalPhysics extends SimpleApplication { + + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestLocalPhysics app = new TestLocalPhysics(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + // Add a physics sphere to the world + Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0)); + physicsSphere.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(physicsSphere); + getPhysicsSpace().add(physicsSphere); + + // Add a physics sphere to the world using the collision shape from sphere one + Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1); + physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0)); + physicsSphere2.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(physicsSphere2); + getPhysicsSpace().add(physicsSphere2); + + // Add a physics box to the world + Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1); + physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f); + physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f)); + physicsBox.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(physicsBox); + getPhysicsSpace().add(physicsBox); + + // Add a physics cylinder to the world + Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1); + physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0)); + physicsCylinder.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(physicsCylinder); + getPhysicsSpace().add(physicsCylinder); + + // an obstacle mesh, does not move (mass=0) + Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0); + node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f)); + node2.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // the floor mesh, does not move (mass=0) + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0); + node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + node3.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + + // Join the physics objects with a Point2Point joint +// PhysicsPoint2PointJoint joint=new PhysicsPoint2PointJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0)); +// PhysicsHingeJoint joint=new PhysicsHingeJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z); +// getPhysicsSpace().add(joint); + + } + + @Override + public void simpleUpdate(float tpf) { + rootNode.rotate(tpf, 0, 0); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsCar.java b/JmeTests/src/jme3test/bullet/TestPhysicsCar.java new file mode 100644 index 0000000..4ba4e06 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestPhysicsCar.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CompoundCollisionShape; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Matrix3f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Cylinder; + +public class TestPhysicsCar extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState; + private VehicleControl vehicle; + private final float accelerationForce = 1000.0f; + private final float brakeForce = 100.0f; + private float steeringValue = 0; + private float accelerationValue = 0; + private Vector3f jumpForce = new Vector3f(0, 3000, 0); + + public static void main(String[] args) { + TestPhysicsCar app = new TestPhysicsCar(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + setupKeys(); + buildPlayer(); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Lefts"); + inputManager.addListener(this, "Rights"); + inputManager.addListener(this, "Ups"); + inputManager.addListener(this, "Downs"); + inputManager.addListener(this, "Space"); + inputManager.addListener(this, "Reset"); + } + + private void buildPlayer() { + Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", ColorRGBA.Red); + + //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0 + //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0 + CompoundCollisionShape compoundShape = new CompoundCollisionShape(); + BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f)); + compoundShape.addChildShape(box, new Vector3f(0, 1, 0)); + + //create vehicle node + Node vehicleNode=new Node("vehicleNode"); + vehicle = new VehicleControl(compoundShape, 400); + vehicleNode.addControl(vehicle); + + //setting suspension values for wheels, this can be a bit tricky + //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en + float stiffness = 60.0f;//200=f1 car + float compValue = .3f; //(should be lower than damp) + float dampValue = .4f; + vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness)); + vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness)); + vehicle.setSuspensionStiffness(stiffness); + vehicle.setMaxSuspensionForce(10000.0f); + + //Create four wheels and add them at their locations + Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0 + Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0 + float radius = 0.5f; + float restLength = 0.3f; + float yOff = 0.5f; + float xOff = 1f; + float zOff = 2f; + + Cylinder wheelMesh = new Cylinder(16, 16, radius, radius * 0.6f, true); + + Node node1 = new Node("wheel 1 node"); + Geometry wheels1 = new Geometry("wheel 1", wheelMesh); + node1.attachChild(wheels1); + wheels1.rotate(0, FastMath.HALF_PI, 0); + wheels1.setMaterial(mat); + vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff), + wheelDirection, wheelAxle, restLength, radius, true); + + Node node2 = new Node("wheel 2 node"); + Geometry wheels2 = new Geometry("wheel 2", wheelMesh); + node2.attachChild(wheels2); + wheels2.rotate(0, FastMath.HALF_PI, 0); + wheels2.setMaterial(mat); + vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff), + wheelDirection, wheelAxle, restLength, radius, true); + + Node node3 = new Node("wheel 3 node"); + Geometry wheels3 = new Geometry("wheel 3", wheelMesh); + node3.attachChild(wheels3); + wheels3.rotate(0, FastMath.HALF_PI, 0); + wheels3.setMaterial(mat); + vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff), + wheelDirection, wheelAxle, restLength, radius, false); + + Node node4 = new Node("wheel 4 node"); + Geometry wheels4 = new Geometry("wheel 4", wheelMesh); + node4.attachChild(wheels4); + wheels4.rotate(0, FastMath.HALF_PI, 0); + wheels4.setMaterial(mat); + vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff), + wheelDirection, wheelAxle, restLength, radius, false); + + vehicleNode.attachChild(node1); + vehicleNode.attachChild(node2); + vehicleNode.attachChild(node3); + vehicleNode.attachChild(node4); + rootNode.attachChild(vehicleNode); + + getPhysicsSpace().add(vehicle); + } + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(vehicle.getPhysicsLocation(), Vector3f.UNIT_Y); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Lefts")) { + if (value) { + steeringValue += .5f; + } else { + steeringValue += -.5f; + } + vehicle.steer(steeringValue); + } else if (binding.equals("Rights")) { + if (value) { + steeringValue += -.5f; + } else { + steeringValue += .5f; + } + vehicle.steer(steeringValue); + } else if (binding.equals("Ups")) { + if (value) { + accelerationValue += accelerationForce; + } else { + accelerationValue -= accelerationForce; + } + vehicle.accelerate(accelerationValue); + } else if (binding.equals("Downs")) { + if (value) { + vehicle.brake(brakeForce); + } else { + vehicle.brake(0f); + } + } else if (binding.equals("Space")) { + if (value) { + vehicle.applyImpulse(jumpForce, Vector3f.ZERO); + } + } else if (binding.equals("Reset")) { + if (value) { + System.out.println("Reset"); + vehicle.setPhysicsLocation(Vector3f.ZERO); + vehicle.setPhysicsRotation(new Matrix3f()); + vehicle.setLinearVelocity(Vector3f.ZERO); + vehicle.setAngularVelocity(Vector3f.ZERO); + vehicle.resetSuspension(); + } else { + } + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java b/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java new file mode 100644 index 0000000..420a5a4 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved.

+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer.

* Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution.

* Neither the name of + * 'jMonkeyEngine' nor the names of its contributors may be used to endorse or + * promote products derived from this software without specific prior written + * permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.CameraControl.ControlDirection; + +/** + * A walking physical character followed by a 3rd person camera. (No animation.) + * @author normenhansen, zathras + */ +public class TestPhysicsCharacter extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState; + private CharacterControl physicsCharacter; + private Node characterNode; + private CameraNode camNode; + boolean rotate = false; + private Vector3f walkDirection = new Vector3f(0,0,0); + private Vector3f viewDirection = new Vector3f(0,0,0); + boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, + leftRotate = false, rightRotate = false; + + public static void main(String[] args) { + TestPhysicsCharacter app = new TestPhysicsCharacter(); + app.start(); + } + + private void setupKeys() { + inputManager.addMapping("Strafe Left", + new KeyTrigger(KeyInput.KEY_Q), + new KeyTrigger(KeyInput.KEY_Z)); + inputManager.addMapping("Strafe Right", + new KeyTrigger(KeyInput.KEY_E), + new KeyTrigger(KeyInput.KEY_X)); + inputManager.addMapping("Rotate Left", + new KeyTrigger(KeyInput.KEY_A), + new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Rotate Right", + new KeyTrigger(KeyInput.KEY_D), + new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("Walk Forward", + new KeyTrigger(KeyInput.KEY_W), + new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("Walk Backward", + new KeyTrigger(KeyInput.KEY_S), + new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("Jump", + new KeyTrigger(KeyInput.KEY_SPACE), + new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("Shoot", + new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(this, "Strafe Left", "Strafe Right"); + inputManager.addListener(this, "Rotate Left", "Rotate Right"); + inputManager.addListener(this, "Walk Forward", "Walk Backward"); + inputManager.addListener(this, "Jump", "Shoot"); + } + @Override + public void simpleInitApp() { + // activate physics + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + + // init a physical test scene + PhysicsTestHelper.createPhysicsTestWorldSoccer(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + setupKeys(); + + // Add a physics character to the world + physicsCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f, 1.8f), .1f); + physicsCharacter.setPhysicsLocation(new Vector3f(0, 1, 0)); + characterNode = new Node("character node"); + Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + model.scale(0.25f); + characterNode.addControl(physicsCharacter); + getPhysicsSpace().add(physicsCharacter); + rootNode.attachChild(characterNode); + characterNode.attachChild(model); + + // set forward camera node that follows the character + camNode = new CameraNode("CamNode", cam); + camNode.setControlDir(ControlDirection.SpatialToCamera); + camNode.setLocalTranslation(new Vector3f(0, 1, -5)); + camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y); + characterNode.attachChild(camNode); + + //disable the default 1st-person flyCam (don't forget this!!) + flyCam.setEnabled(false); + + } + + @Override + public void simpleUpdate(float tpf) { + Vector3f camDir = cam.getDirection().mult(0.2f); + Vector3f camLeft = cam.getLeft().mult(0.2f); + camDir.y = 0; + camLeft.y = 0; + viewDirection.set(camDir); + walkDirection.set(0, 0, 0); + if (leftStrafe) { + walkDirection.addLocal(camLeft); + } else + if (rightStrafe) { + walkDirection.addLocal(camLeft.negate()); + } + if (leftRotate) { + viewDirection.addLocal(camLeft.mult(0.02f)); + } else + if (rightRotate) { + viewDirection.addLocal(camLeft.mult(0.02f).negate()); + } + if (forward) { + walkDirection.addLocal(camDir); + } else + if (backward) { + walkDirection.addLocal(camDir.negate()); + } + physicsCharacter.setWalkDirection(walkDirection); + physicsCharacter.setViewDirection(viewDirection); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Strafe Left")) { + if (value) { + leftStrafe = true; + } else { + leftStrafe = false; + } + } else if (binding.equals("Strafe Right")) { + if (value) { + rightStrafe = true; + } else { + rightStrafe = false; + } + } else if (binding.equals("Rotate Left")) { + if (value) { + leftRotate = true; + } else { + leftRotate = false; + } + } else if (binding.equals("Rotate Right")) { + if (value) { + rightRotate = true; + } else { + rightRotate = false; + } + } else if (binding.equals("Walk Forward")) { + if (value) { + forward = true; + } else { + forward = false; + } + } else if (binding.equals("Walk Backward")) { + if (value) { + backward = true; + } else { + backward = false; + } + } else if (binding.equals("Jump")) { + physicsCharacter.jump(); + } + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } +} diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java b/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java new file mode 100644 index 0000000..029892a --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.joints.HingeJoint; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +public class TestPhysicsHingeJoint extends SimpleApplication implements AnalogListener { + private BulletAppState bulletAppState; + private HingeJoint joint; + + public static void main(String[] args) { + TestPhysicsHingeJoint app = new TestPhysicsHingeJoint(); + app.start(); + } + + private void setupKeys() { + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Swing", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, "Left", "Right", "Swing"); + } + + public void onAnalog(String binding, float value, float tpf) { + if(binding.equals("Left")){ + joint.enableMotor(true, 1, .1f); + } + else if(binding.equals("Right")){ + joint.enableMotor(true, -1, .1f); + } + else if(binding.equals("Swing")){ + joint.enableMotor(false, 0, 0); + } + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + setupKeys(); + setupJoint(); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + public void setupJoint() { + Node holderNode=PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f( .1f, .1f, .1f)),0); + holderNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,0,0f)); + rootNode.attachChild(holderNode); + getPhysicsSpace().add(holderNode); + + Node hammerNode=PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f( .3f, .3f, .3f)),1); + hammerNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,-1,0f)); + rootNode.attachChild(hammerNode); + getPhysicsSpace().add(hammerNode); + + joint=new HingeJoint(holderNode.getControl(RigidBodyControl.class), hammerNode.getControl(RigidBodyControl.class), Vector3f.ZERO, new Vector3f(0f,-1,0f), Vector3f.UNIT_Z, Vector3f.UNIT_Z); + getPhysicsSpace().add(joint); + } + + @Override + public void simpleUpdate(float tpf) { + + } + + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java b/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java new file mode 100644 index 0000000..24665b4 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java @@ -0,0 +1,69 @@ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.PhysicsRayTestResult; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.util.CollisionShapeFactory; +import com.jme3.font.BitmapText; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import java.util.List; + +/** + * + * @author @wezrule + */ +public class TestPhysicsRayCast extends SimpleApplication { + + private BulletAppState bulletAppState = new BulletAppState(); + + public static void main(String[] args) { + new TestPhysicsRayCast().start(); + } + + @Override + public void simpleInitApp() { + stateManager.attach(bulletAppState); + initCrossHair(); + + Spatial s = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml"); + s.setLocalScale(0.1f); + + CollisionShape collisionShape = CollisionShapeFactory.createMeshShape(s); + Node n = new Node("elephant"); + n.addControl(new RigidBodyControl(collisionShape, 1)); + n.getControl(RigidBodyControl.class).setKinematic(true); + bulletAppState.getPhysicsSpace().add(n); + rootNode.attachChild(n); + bulletAppState.setDebugEnabled(true); + } + + @Override + public void simpleUpdate(float tpf) { + float rayLength = 50f; + Vector3f start = cam.getLocation(); + Vector3f end = cam.getDirection().scaleAdd(rayLength, start); + List rayTest + = bulletAppState.getPhysicsSpace().rayTest(start, end); + if (rayTest.size() > 0) { + PhysicsRayTestResult get = rayTest.get(0); + PhysicsCollisionObject collisionObject = get.getCollisionObject(); + // Display the name of the 1st object in place of FPS. + fpsText.setText(collisionObject.getUserObject().toString()); + } else { + // Provide prompt feedback that no collision object was hit. + fpsText.setText("MISSING"); + } + } + + private void initCrossHair() { + BitmapText bitmapText = new BitmapText(guiFont); + bitmapText.setText("+"); + bitmapText.setLocalTranslation((settings.getWidth() - bitmapText.getLineWidth())*0.5f, (settings.getHeight() + bitmapText.getLineHeight())*0.5f, 0); + guiNode.attachChild(bitmapText); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java b/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java new file mode 100644 index 0000000..7d94e05 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.*; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.joints.HingeJoint; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.export.binary.BinaryImporter; +import com.jme3.math.Plane; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This is a basic Test of jbullet-jme functions + * + * @author normenhansen + */ +public class TestPhysicsReadWrite extends SimpleApplication{ + private BulletAppState bulletAppState; + private Node physicsRootNode; + public static void main(String[] args){ + TestPhysicsReadWrite app = new TestPhysicsReadWrite(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + physicsRootNode=new Node("PhysicsRootNode"); + rootNode.attachChild(physicsRootNode); + + // Add a physics sphere to the world + Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0)); + rootNode.attachChild(physicsSphere); + getPhysicsSpace().add(physicsSphere); + + // Add a physics sphere to the world using the collision shape from sphere one + Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1); + physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0)); + rootNode.attachChild(physicsSphere2); + getPhysicsSpace().add(physicsSphere2); + + // Add a physics box to the world + Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1); + physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f); + physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f)); + rootNode.attachChild(physicsBox); + getPhysicsSpace().add(physicsBox); + + // Add a physics cylinder to the world + Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1); + physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0)); + rootNode.attachChild(physicsCylinder); + getPhysicsSpace().add(physicsCylinder); + + // an obstacle mesh, does not move (mass=0) + Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0); + node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f)); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // the floor mesh, does not move (mass=0) + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0); + node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + + // Join the physics objects with a Point2Point joint + HingeJoint joint=new HingeJoint(physicsSphere.getControl(RigidBodyControl.class), physicsBox.getControl(RigidBodyControl.class), new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z); + getPhysicsSpace().add(joint); + + //save and load the physicsRootNode + try { + //remove all physics objects from physics space + getPhysicsSpace().removeAll(physicsRootNode); + physicsRootNode.removeFromParent(); + //export to byte array + ByteArrayOutputStream bout=new ByteArrayOutputStream(); + BinaryExporter.getInstance().save(physicsRootNode, bout); + //import from byte array + ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray()); + BinaryImporter imp=BinaryImporter.getInstance(); + imp.setAssetManager(assetManager); + Node newPhysicsRootNode=(Node)imp.load(bin); + //add all physics objects to physics space + getPhysicsSpace().addAll(newPhysicsRootNode); + rootNode.attachChild(newPhysicsRootNode); + } catch (IOException ex) { + Logger.getLogger(TestPhysicsReadWrite.class.getName()).log(Level.SEVERE, null, ex); + } + + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } + +} diff --git a/JmeTests/src/jme3test/bullet/TestQ3.java b/JmeTests/src/jme3test/bullet/TestQ3.java new file mode 100644 index 0000000..01d0c9a --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestQ3.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.objects.PhysicsCharacter; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.MaterialList; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.plugins.ogre.OgreMeshKey; +import java.io.File; + +public class TestQ3 extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState; + private Node gameLevel; + private PhysicsCharacter player; + private Vector3f walkDirection = new Vector3f(); + private static boolean useHttp = false; + private boolean left=false,right=false,up=false,down=false; + + public static void main(String[] args) { + File file = new File("quake3level.zip"); + if (!file.exists()) { + useHttp = true; + } + TestQ3 app = new TestQ3(); + app.start(); + } + + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + flyCam.setMoveSpeed(100); + setupKeys(); + + this.cam.setFrustumFar(2000); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White.clone().multLocal(2)); + dl.setDirection(new Vector3f(-1, -1, -1).normalize()); + rootNode.addLight(dl); + + AmbientLight am = new AmbientLight(); + am.setColor(ColorRGBA.White.mult(2)); + rootNode.addLight(am); + + // load the level from zip or http zip + if (useHttp) { + assetManager.registerLocator( + "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/quake3level.zip", + HttpZipLocator.class); + } else { + assetManager.registerLocator("quake3level.zip", ZipLocator.class); + } + + // create the geometry and attach it + MaterialList matList = (MaterialList) assetManager.loadAsset("Scene.material"); + OgreMeshKey key = new OgreMeshKey("main.meshxml", matList); + gameLevel = (Node) assetManager.loadAsset(key); + gameLevel.setLocalScale(0.1f); + + // add a physics control, it will generate a MeshCollisionShape based on the gameLevel + gameLevel.addControl(new RigidBodyControl(0)); + + player = new PhysicsCharacter(new SphereCollisionShape(5), .01f); + player.setJumpSpeed(20); + player.setFallSpeed(30); + player.setGravity(30); + + player.setPhysicsLocation(new Vector3f(60, 10, -60)); + + rootNode.attachChild(gameLevel); + + getPhysicsSpace().addAll(gameLevel); + getPhysicsSpace().add(player); + } + + private PhysicsSpace getPhysicsSpace(){ + return bulletAppState.getPhysicsSpace(); + } + + @Override + public void simpleUpdate(float tpf) { + Vector3f camDir = cam.getDirection().clone().multLocal(0.6f); + Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f); + walkDirection.set(0,0,0); + if(left) + walkDirection.addLocal(camLeft); + if(right) + walkDirection.addLocal(camLeft.negate()); + if(up) + walkDirection.addLocal(camDir); + if(down) + walkDirection.addLocal(camDir.negate()); + player.setWalkDirection(walkDirection); + cam.setLocation(player.getPhysicsLocation()); + } + + private void setupKeys() { + inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this,"Lefts"); + inputManager.addListener(this,"Rights"); + inputManager.addListener(this,"Ups"); + inputManager.addListener(this,"Downs"); + inputManager.addListener(this,"Space"); + } + + public void onAction(String binding, boolean value, float tpf) { + + if (binding.equals("Lefts")) { + if(value) + left=true; + else + left=false; + } else if (binding.equals("Rights")) { + if(value) + right=true; + else + right=false; + } else if (binding.equals("Ups")) { + if(value) + up=true; + else + up=false; + } else if (binding.equals("Downs")) { + if(value) + down=true; + else + down=false; + } else if (binding.equals("Space")) { + player.jump(); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestRagDoll.java b/JmeTests/src/jme3test/bullet/TestRagDoll.java new file mode 100644 index 0000000..2752ce5 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestRagDoll.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.joints.ConeJoint; +import com.jme3.bullet.joints.PhysicsJoint; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +/** + * + * @author normenhansen + */ +public class TestRagDoll extends SimpleApplication implements ActionListener { + + private BulletAppState bulletAppState = new BulletAppState(); + private Node ragDoll = new Node(); + private Node shoulders; + private Vector3f upforce = new Vector3f(0, 200, 0); + private boolean applyForce = false; + + public static void main(String[] args) { + TestRagDoll app = new TestRagDoll(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + inputManager.addMapping("Pull ragdoll up", new MouseButtonTrigger(0)); + inputManager.addListener(this, "Pull ragdoll up"); + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + createRagDoll(); + } + + private void createRagDoll() { + shoulders = createLimb(0.2f, 1.0f, new Vector3f(0.00f, 1.5f, 0), true); + Node uArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f, 0.8f, 0), false); + Node uArmR = createLimb(0.2f, 0.5f, new Vector3f(0.75f, 0.8f, 0), false); + Node lArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f, -0.2f, 0), false); + Node lArmR = createLimb(0.2f, 0.5f, new Vector3f(0.75f, -0.2f, 0), false); + Node body = createLimb(0.2f, 1.0f, new Vector3f(0.00f, 0.5f, 0), false); + Node hips = createLimb(0.2f, 0.5f, new Vector3f(0.00f, -0.5f, 0), true); + Node uLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f, -1.2f, 0), false); + Node uLegR = createLimb(0.2f, 0.5f, new Vector3f(0.25f, -1.2f, 0), false); + Node lLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f, -2.2f, 0), false); + Node lLegR = createLimb(0.2f, 0.5f, new Vector3f(0.25f, -2.2f, 0), false); + + join(body, shoulders, new Vector3f(0f, 1.4f, 0)); + join(body, hips, new Vector3f(0f, -0.5f, 0)); + + join(uArmL, shoulders, new Vector3f(-0.75f, 1.4f, 0)); + join(uArmR, shoulders, new Vector3f(0.75f, 1.4f, 0)); + join(uArmL, lArmL, new Vector3f(-0.75f, .4f, 0)); + join(uArmR, lArmR, new Vector3f(0.75f, .4f, 0)); + + join(uLegL, hips, new Vector3f(-.25f, -0.5f, 0)); + join(uLegR, hips, new Vector3f(.25f, -0.5f, 0)); + join(uLegL, lLegL, new Vector3f(-.25f, -1.7f, 0)); + join(uLegR, lLegR, new Vector3f(.25f, -1.7f, 0)); + + ragDoll.attachChild(shoulders); + ragDoll.attachChild(body); + ragDoll.attachChild(hips); + ragDoll.attachChild(uArmL); + ragDoll.attachChild(uArmR); + ragDoll.attachChild(lArmL); + ragDoll.attachChild(lArmR); + ragDoll.attachChild(uLegL); + ragDoll.attachChild(uLegR); + ragDoll.attachChild(lLegL); + ragDoll.attachChild(lLegR); + + rootNode.attachChild(ragDoll); + bulletAppState.getPhysicsSpace().addAll(ragDoll); + } + + private Node createLimb(float width, float height, Vector3f location, boolean rotate) { + int axis = rotate ? PhysicsSpace.AXIS_X : PhysicsSpace.AXIS_Y; + CapsuleCollisionShape shape = new CapsuleCollisionShape(width, height, axis); + Node node = new Node("Limb"); + RigidBodyControl rigidBodyControl = new RigidBodyControl(shape, 1); + node.setLocalTranslation(location); + node.addControl(rigidBodyControl); + return node; + } + + private PhysicsJoint join(Node A, Node B, Vector3f connectionPoint) { + Vector3f pivotA = A.worldToLocal(connectionPoint, new Vector3f()); + Vector3f pivotB = B.worldToLocal(connectionPoint, new Vector3f()); + ConeJoint joint = new ConeJoint(A.getControl(RigidBodyControl.class), B.getControl(RigidBodyControl.class), pivotA, pivotB); + joint.setLimit(1f, 1f, 0); + return joint; + } + + public void onAction(String string, boolean bln, float tpf) { + if ("Pull ragdoll up".equals(string)) { + if (bln) { + shoulders.getControl(RigidBodyControl.class).activate(); + applyForce = true; + } else { + applyForce = false; + } + } + } + + @Override + public void simpleUpdate(float tpf) { + if (applyForce) { + shoulders.getControl(RigidBodyControl.class).applyForce(upforce, Vector3f.ZERO); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java b/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java new file mode 100644 index 0000000..5b9e948 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.control.KinematicRagdollControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.texture.Texture; + +/** + * @author normenhansen + */ +public class TestRagdollCharacter extends SimpleApplication implements AnimEventListener, ActionListener { + + BulletAppState bulletAppState; + Node model; + KinematicRagdollControl ragdoll; + boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false, + leftRotate = false, rightRotate = false; + AnimControl animControl; + AnimChannel animChannel; + + public static void main(String[] args) { + TestRagdollCharacter app = new TestRagdollCharacter(); + app.start(); + } + + public void simpleInitApp() { + setupKeys(); + + bulletAppState = new BulletAppState(); + bulletAppState.setEnabled(true); + stateManager.attach(bulletAppState); + + +// bulletAppState.getPhysicsSpace().enableDebug(assetManager); + PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); + initWall(2,1,1); + setupLight(); + + cam.setLocation(new Vector3f(-8,0,-4)); + cam.lookAt(new Vector3f(4,0,-7), Vector3f.UNIT_Y); + + model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + model.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y); + model.setLocalTranslation(4, 0, -7f); + + ragdoll = new KinematicRagdollControl(0.5f); + model.addControl(ragdoll); + + getPhysicsSpace().add(ragdoll); + speed = 1.3f; + + rootNode.attachChild(model); + + + AnimControl control = model.getControl(AnimControl.class); + animChannel = control.createChannel(); + animChannel.setAnim("IdleTop"); + control.addListener(this); + + } + + private void setupLight() { + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + private void setupKeys() { + inputManager.addMapping("Rotate Left", + new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("Rotate Right", + new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Walk Forward", + new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("Walk Backward", + new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("Slice", + new KeyTrigger(KeyInput.KEY_SPACE), + new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(this, "Strafe Left", "Strafe Right"); + inputManager.addListener(this, "Rotate Left", "Rotate Right"); + inputManager.addListener(this, "Walk Forward", "Walk Backward"); + inputManager.addListener(this, "Slice"); + } + + public void initWall(float bLength, float bWidth, float bHeight) { + Box brick = new Box(bLength, bHeight, bWidth); + brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); + Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + mat2.setTexture("ColorMap", tex); + + float startpt = bLength / 4; + float height = -5; + for (int j = 0; j < 15; j++) { + for (int i = 0; i < 4; i++) { + Vector3f ori = new Vector3f(i * bLength * 2 + startpt, bHeight + height, -10); + Geometry reBoxg = new Geometry("brick", brick); + reBoxg.setMaterial(mat2); + reBoxg.setLocalTranslation(ori); + //for geometry with sphere mesh the physics system automatically uses a sphere collision shape + reBoxg.addControl(new RigidBodyControl(1.5f)); + reBoxg.setShadowMode(ShadowMode.CastAndReceive); + reBoxg.getControl(RigidBodyControl.class).setFriction(0.6f); + this.rootNode.attachChild(reBoxg); + this.getPhysicsSpace().add(reBoxg); + } + startpt = -startpt; + height += 2 * bHeight; + } + } + + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + + if (channel.getAnimationName().equals("SliceHorizontal")) { + channel.setLoopMode(LoopMode.DontLoop); + channel.setAnim("IdleTop", 5); + channel.setLoopMode(LoopMode.Loop); + } + + } + + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Rotate Left")) { + if (value) { + leftRotate = true; + } else { + leftRotate = false; + } + } else if (binding.equals("Rotate Right")) { + if (value) { + rightRotate = true; + } else { + rightRotate = false; + } + } else if (binding.equals("Walk Forward")) { + if (value) { + forward = true; + } else { + forward = false; + } + } else if (binding.equals("Walk Backward")) { + if (value) { + backward = true; + } else { + backward = false; + } + } else if (binding.equals("Slice")) { + if (value) { + animChannel.setAnim("SliceHorizontal"); + animChannel.setSpeed(0.3f); + } + } + } + + @Override + public void simpleUpdate(float tpf) { + if(forward){ + model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(tpf)); + }else if(backward){ + model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(-tpf)); + }else if(leftRotate){ + model.rotate(0, tpf, 0); + }else if(rightRotate){ + model.rotate(0, -tpf, 0); + } + fpsText.setText(cam.getLocation() + "/" + cam.getRotation()); + } + +} diff --git a/JmeTests/src/jme3test/bullet/TestSimplePhysics.java b/JmeTests/src/jme3test/bullet/TestSimplePhysics.java new file mode 100644 index 0000000..9cf2808 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestSimplePhysics.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.*; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Plane; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; + +/** + * This is a basic Test of jbullet-jme functions + * + * @author normenhansen + */ +public class TestSimplePhysics extends SimpleApplication { + + private BulletAppState bulletAppState; + + public static void main(String[] args) { + TestSimplePhysics app = new TestSimplePhysics(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + bulletAppState.setDebugEnabled(true); + + // Add a physics sphere to the world + Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1); + physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0)); + rootNode.attachChild(physicsSphere); + getPhysicsSpace().add(physicsSphere); + + // Add a physics sphere to the world using the collision shape from sphere one + Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1); + physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0)); + rootNode.attachChild(physicsSphere2); + getPhysicsSpace().add(physicsSphere2); + + // Add a physics box to the world + Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1); + physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f); + physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f)); + rootNode.attachChild(physicsBox); + getPhysicsSpace().add(physicsBox); + + // Add a physics cylinder to the world + Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1); + physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0)); + rootNode.attachChild(physicsCylinder); + getPhysicsSpace().add(physicsCylinder); + + // an obstacle mesh, does not move (mass=0) + Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0); + node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f)); + rootNode.attachChild(node2); + getPhysicsSpace().add(node2); + + // the floor mesh, does not move (mass=0) + Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0); + node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f)); + rootNode.attachChild(node3); + getPhysicsSpace().add(node3); + + // Join the physics objects with a Point2Point joint +// PhysicsPoint2PointJoint joint=new PhysicsPoint2PointJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0)); +// PhysicsHingeJoint joint=new PhysicsHingeJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z); +// getPhysicsSpace().add(joint); + + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } +} diff --git a/JmeTests/src/jme3test/bullet/TestSweepTest.java b/JmeTests/src/jme3test/bullet/TestSweepTest.java new file mode 100644 index 0000000..da9089c --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestSweepTest.java @@ -0,0 +1,79 @@ +package jme3test.bullet; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.PhysicsSweepTestResult; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.math.Transform; +import com.jme3.scene.Node; +import java.util.List; + +/** + * + * A spatial moves and sweeps its next movement for obstacles before moving + * there Run this example with Vsync enabled + * + * @author + * @wezrule + */ +public class TestSweepTest extends SimpleApplication { + + private BulletAppState bulletAppState = new BulletAppState(); + private CapsuleCollisionShape obstacleCollisionShape; + private CapsuleCollisionShape capsuleCollisionShape; + private Node capsule; + private Node obstacle; + private float dist = .5f; + + public static void main(String[] args) { + new TestSweepTest().start(); + } + + @Override + public void simpleInitApp() { + obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f); + capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f); + + stateManager.attach(bulletAppState); + + capsule = new Node("capsule"); + capsule.move(-2, 0, 0); + capsule.addControl(new RigidBodyControl(capsuleCollisionShape, 1)); + capsule.getControl(RigidBodyControl.class).setKinematic(true); + bulletAppState.getPhysicsSpace().add(capsule); + rootNode.attachChild(capsule); + + obstacle = new Node("obstacle"); + obstacle.move(2, 0, 0); + RigidBodyControl bodyControl = new RigidBodyControl(obstacleCollisionShape, 0); + obstacle.addControl(bodyControl); + bulletAppState.getPhysicsSpace().add(obstacle); + rootNode.attachChild(obstacle); + + bulletAppState.setDebugEnabled(true); + } + + @Override + public void simpleUpdate(float tpf) { + + float move = tpf * 1; + boolean colliding = false; + + List sweepTest = bulletAppState.getPhysicsSpace().sweepTest(capsuleCollisionShape, new Transform(capsule.getWorldTranslation()), new Transform(capsule.getWorldTranslation().add(dist, 0, 0))); + + for (PhysicsSweepTestResult result : sweepTest) { + if (result.getCollisionObject().getCollisionShape() != capsuleCollisionShape) { + PhysicsCollisionObject collisionObject = result.getCollisionObject(); + fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString()); + colliding = true; + } + } + + if (!colliding) { + // if the sweep is clear then move the spatial + capsule.move(move, 0, 0); + } + } +} diff --git a/JmeTests/src/jme3test/bullet/TestWalkingChar.java b/JmeTests/src/jme3test/bullet/TestWalkingChar.java new file mode 100644 index 0000000..c2c4866 --- /dev/null +++ b/JmeTests/src/jme3test/bullet/TestWalkingChar.java @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.bullet; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionEvent; +import com.jme3.bullet.collision.PhysicsCollisionListener; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.util.CollisionShapeFactory; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import java.util.ArrayList; +import java.util.List; + +/** + * A walking animated character followed by a 3rd person camera on a terrain with LOD. + * @author normenhansen + */ +public class TestWalkingChar extends SimpleApplication implements ActionListener, PhysicsCollisionListener, AnimEventListener { + + private BulletAppState bulletAppState; + //character + CharacterControl character; + Node model; + //temp vectors + Vector3f walkDirection = new Vector3f(); + //terrain + TerrainQuad terrain; + RigidBodyControl terrainPhysicsNode; + //Materials + Material matRock; + Material matBullet; + //animation + AnimChannel animationChannel; + AnimChannel shootingChannel; + AnimControl animationControl; + float airTime = 0; + //camera + boolean left = false, right = false, up = false, down = false; + ChaseCamera chaseCam; + //bullet + Sphere bullet; + SphereCollisionShape bulletCollisionShape; + //explosion + ParticleEmitter effect; + //brick wall + Box brick; + float bLength = 0.8f; + float bWidth = 0.4f; + float bHeight = 0.4f; + FilterPostProcessor fpp; + + public static void main(String[] args) { + TestWalkingChar app = new TestWalkingChar(); + app.start(); + } + + @Override + public void simpleInitApp() { + bulletAppState = new BulletAppState(); + bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); + stateManager.attach(bulletAppState); + setupKeys(); + prepareBullet(); + prepareEffect(); + createLight(); + createSky(); + createTerrain(); + createWall(); + createCharacter(); + setupChaseCamera(); + setupAnimationController(); + setupFilter(); + } + + private void setupFilter() { + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects); + fpp.addFilter(bloom); + viewPort.addProcessor(fpp); + } + + private PhysicsSpace getPhysicsSpace() { + return bulletAppState.getPhysicsSpace(); + } + + private void setupKeys() { + inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addListener(this, "wireframe"); + inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, "CharLeft"); + inputManager.addListener(this, "CharRight"); + inputManager.addListener(this, "CharUp"); + inputManager.addListener(this, "CharDown"); + inputManager.addListener(this, "CharSpace"); + inputManager.addListener(this, "CharShoot"); + } + + private void createWall() { + float xOff = -144; + float zOff = -40; + float startpt = bLength / 4 - xOff; + float height = 6.1f; + brick = new Box(bLength, bHeight, bWidth); + brick.scaleTextureCoordinates(new Vector2f(1f, .5f)); + for (int j = 0; j < 15; j++) { + for (int i = 0; i < 4; i++) { + Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, zOff); + addBrick(vt); + } + startpt = -startpt; + height += 1.01f * bHeight; + } + } + + private void addBrick(Vector3f ori) { + Geometry reBoxg = new Geometry("brick", brick); + reBoxg.setMaterial(matBullet); + reBoxg.setLocalTranslation(ori); + reBoxg.addControl(new RigidBodyControl(1.5f)); + reBoxg.setShadowMode(ShadowMode.CastAndReceive); + this.rootNode.attachChild(reBoxg); + this.getPhysicsSpace().add(reBoxg); + } + + private void prepareBullet() { + bullet = new Sphere(32, 32, 0.4f, true, false); + bullet.setTextureMode(TextureMode.Projected); + bulletCollisionShape = new SphereCollisionShape(0.4f); + matBullet = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + matBullet.setColor("Color", ColorRGBA.Green); + matBullet.setColor("GlowColor", ColorRGBA.Green); + getPhysicsSpace().addCollisionListener(this); + } + + private void prepareEffect() { + int COUNT_FACTOR = 1; + float COUNT_FACTOR_F = 1f; + effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR); + effect.setSelectRandomImage(true); + effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F))); + effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f)); + effect.setStartSize(1.3f); + effect.setEndSize(2f); + effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); + effect.setParticlesPerSec(0); + effect.setGravity(0, -5, 0); + effect.setLowLife(.4f); + effect.setHighLife(.5f); + effect.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 7, 0)); + effect.getParticleInfluencer().setVelocityVariation(1f); + effect.setImagesX(2); + effect.setImagesY(2); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + effect.setMaterial(mat); +// effect.setLocalScale(100); + rootNode.attachChild(effect); + } + + private void createLight() { + Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal(); + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(direction); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + } + + private void createSky() { + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + } + + private void createTerrain() { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + + } catch (Exception e) { + e.printStackTrace(); + } + + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + TerrainLodControl control = new TerrainLodControl(terrain, cameras); + terrain.addControl(control); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(2, 2, 2)); + + terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0); + terrain.addControl(terrainPhysicsNode); + rootNode.attachChild(terrain); + getPhysicsSpace().add(terrainPhysicsNode); + } + + private void createCharacter() { + CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f); + character = new CharacterControl(capsule, 0.01f); + model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + //model.setLocalScale(0.5f); + model.addControl(character); + character.setPhysicsLocation(new Vector3f(-140, 40, -10)); + rootNode.attachChild(model); + getPhysicsSpace().add(character); + } + + private void setupChaseCamera() { + flyCam.setEnabled(false); + chaseCam = new ChaseCamera(cam, model, inputManager); + } + + private void setupAnimationController() { + animationControl = model.getControl(AnimControl.class); + animationControl.addListener(this); + animationChannel = animationControl.createChannel(); + shootingChannel = animationControl.createChannel(); + shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right")); + shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right")); + shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right")); + } + + @Override + public void simpleUpdate(float tpf) { + Vector3f camDir = cam.getDirection().clone().multLocal(0.1f); + Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f); + camDir.y = 0; + camLeft.y = 0; + walkDirection.set(0, 0, 0); + if (left) { + walkDirection.addLocal(camLeft); + } + if (right) { + walkDirection.addLocal(camLeft.negate()); + } + if (up) { + walkDirection.addLocal(camDir); + } + if (down) { + walkDirection.addLocal(camDir.negate()); + } + if (!character.onGround()) { + airTime = airTime + tpf; + } else { + airTime = 0; + } + if (walkDirection.length() == 0) { + if (!"stand".equals(animationChannel.getAnimationName())) { + animationChannel.setAnim("stand", 1f); + } + } else { + character.setViewDirection(walkDirection); + if (airTime > .3f) { + if (!"stand".equals(animationChannel.getAnimationName())) { + animationChannel.setAnim("stand"); + } + } else if (!"Walk".equals(animationChannel.getAnimationName())) { + animationChannel.setAnim("Walk", 0.7f); + } + } + character.setWalkDirection(walkDirection); + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("CharLeft")) { + if (value) { + left = true; + } else { + left = false; + } + } else if (binding.equals("CharRight")) { + if (value) { + right = true; + } else { + right = false; + } + } else if (binding.equals("CharUp")) { + if (value) { + up = true; + } else { + up = false; + } + } else if (binding.equals("CharDown")) { + if (value) { + down = true; + } else { + down = false; + } + } else if (binding.equals("CharSpace")) { + character.jump(); + } else if (binding.equals("CharShoot") && !value) { + bulletControl(); + } + } + + private void bulletControl() { + shootingChannel.setAnim("Dodge", 0.1f); + shootingChannel.setLoopMode(LoopMode.DontLoop); + Geometry bulletg = new Geometry("bullet", bullet); + bulletg.setMaterial(matBullet); + bulletg.setShadowMode(ShadowMode.CastAndReceive); + bulletg.setLocalTranslation(character.getPhysicsLocation().add(cam.getDirection().mult(5))); + RigidBodyControl bulletControl = new BombControl(bulletCollisionShape, 1); + bulletControl.setCcdMotionThreshold(0.1f); + bulletControl.setLinearVelocity(cam.getDirection().mult(80)); + bulletg.addControl(bulletControl); + rootNode.attachChild(bulletg); + getPhysicsSpace().add(bulletControl); + } + + public void collision(PhysicsCollisionEvent event) { + if (event.getObjectA() instanceof BombControl) { + final Spatial node = event.getNodeA(); + effect.killAllParticles(); + effect.setLocalTranslation(node.getLocalTranslation()); + effect.emitAllParticles(); + } else if (event.getObjectB() instanceof BombControl) { + final Spatial node = event.getNodeB(); + effect.killAllParticles(); + effect.setLocalTranslation(node.getLocalTranslation()); + effect.emitAllParticles(); + } + } + + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + if (channel == shootingChannel) { + channel.setAnim("stand"); + } + } + + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } +} diff --git a/JmeTests/src/jme3test/collision/RayTrace.java b/JmeTests/src/jme3test/collision/RayTrace.java new file mode 100644 index 0000000..d7cc5a2 --- /dev/null +++ b/JmeTests/src/jme3test/collision/RayTrace.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.collision; + +import com.jme3.collision.CollisionResults; +import com.jme3.math.Ray; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Spatial; +import java.awt.FlowLayout; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class RayTrace { + + private BufferedImage image; + private Camera cam; + private Spatial scene; + private CollisionResults results = new CollisionResults(); + private JFrame frame; + private JLabel label; + + public RayTrace(Spatial scene, Camera cam, int width, int height){ + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + this.scene = scene; + this.cam = cam; + } + + public void show(){ + frame = new JFrame("HDR View"); + label = new JLabel(new ImageIcon(image)); + frame.getContentPane().add(label); + frame.setLayout(new FlowLayout()); + frame.pack(); + frame.setVisible(true); + } + + public void update(){ + int w = image.getWidth(); + int h = image.getHeight(); + + float wr = (float) cam.getWidth() / image.getWidth(); + float hr = (float) cam.getHeight() / image.getHeight(); + + scene.updateGeometricState(); + + for (int y = 0; y < h; y++){ + for (int x = 0; x < w; x++){ + Vector2f v = new Vector2f(x * wr,y * hr); + Vector3f pos = cam.getWorldCoordinates(v, 0.0f); + Vector3f dir = cam.getWorldCoordinates(v, 0.3f); + dir.subtractLocal(pos).normalizeLocal(); + + Ray r = new Ray(pos, dir); + + results.clear(); + scene.collideWith(r, results); + if (results.size() > 0){ + image.setRGB(x, h - y - 1, 0xFFFFFFFF); + }else{ + image.setRGB(x, h - y - 1, 0xFF000000); + } + } + } + + label.repaint(); + } + +} diff --git a/JmeTests/src/jme3test/collision/TestMousePick.java b/JmeTests/src/jme3test/collision/TestMousePick.java new file mode 100644 index 0000000..9f58b7f --- /dev/null +++ b/JmeTests/src/jme3test/collision/TestMousePick.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.collision; + +import com.jme3.app.SimpleApplication; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Ray; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.shape.Box; + +public class TestMousePick extends SimpleApplication { + + public static void main(String[] args) { + TestMousePick app = new TestMousePick(); + app.start(); + } + + Node shootables; + Geometry mark; + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + initMark(); // a red sphere to mark the hit + + /** create four colored boxes and a floor to shoot at: */ + shootables = new Node("Shootables"); + rootNode.attachChild(shootables); + shootables.attachChild(makeCube("a Dragon", -2f, 0f, 1f)); + shootables.attachChild(makeCube("a tin can", 1f, -2f, 0f)); + shootables.attachChild(makeCube("the Sheriff", 0f, 1f, -2f)); + shootables.attachChild(makeCube("the Deputy", 1f, 0f, -4f)); + shootables.attachChild(makeFloor()); + shootables.attachChild(makeCharacter()); + } + + @Override + public void simpleUpdate(float tpf){ + Vector3f origin = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f); + Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f); + direction.subtractLocal(origin).normalizeLocal(); + + Ray ray = new Ray(origin, direction); + CollisionResults results = new CollisionResults(); + shootables.collideWith(ray, results); +// System.out.println("----- Collisions? " + results.size() + "-----"); +// for (int i = 0; i < results.size(); i++) { +// // For each hit, we know distance, impact point, name of geometry. +// float dist = results.getCollision(i).getDistance(); +// Vector3f pt = results.getCollision(i).getWorldContactPoint(); +// String hit = results.getCollision(i).getGeometry().getName(); +// System.out.println("* Collision #" + i); +// System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away."); +// } + if (results.size() > 0) { + CollisionResult closest = results.getClosestCollision(); + mark.setLocalTranslation(closest.getContactPoint()); + + Quaternion q = new Quaternion(); + q.lookAt(closest.getContactNormal(), Vector3f.UNIT_Y); + mark.setLocalRotation(q); + + rootNode.attachChild(mark); + } else { + rootNode.detachChild(mark); + } + } + + /** A cube object for target practice */ + protected Geometry makeCube(String name, float x, float y, float z) { + Box box = new Box(1, 1, 1); + Geometry cube = new Geometry(name, box); + cube.setLocalTranslation(x, y, z); + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.randomColor()); + cube.setMaterial(mat1); + return cube; + } + + /** A floor to show that the "shot" can go through several objects. */ + protected Geometry makeFloor() { + Box box = new Box(15, .2f, 15); + Geometry floor = new Geometry("the Floor", box); + floor.setLocalTranslation(0, -4, -5); + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Gray); + floor.setMaterial(mat1); + return floor; + } + + /** A red ball that marks the last spot that was "hit" by the "shot". */ + protected void initMark() { + Arrow arrow = new Arrow(Vector3f.UNIT_Z.mult(2f)); + + //Sphere sphere = new Sphere(30, 30, 0.2f); + mark = new Geometry("BOOM!", arrow); + //mark = new Geometry("BOOM!", sphere); + Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mark_mat.getAdditionalRenderState().setLineWidth(3); + mark_mat.setColor("Color", ColorRGBA.Red); + mark.setMaterial(mark_mat); + } + + protected Spatial makeCharacter() { + // load a character from jme3test-test-data + Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + golem.scale(0.5f); + golem.setLocalTranslation(-1.0f, -1.5f, -0.6f); + + // We must add a light to make the model visible + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal()); + golem.addLight(sun); + return golem; + } +} diff --git a/JmeTests/src/jme3test/collision/TestRayCasting.java b/JmeTests/src/jme3test/collision/TestRayCasting.java new file mode 100644 index 0000000..06b07e8 --- /dev/null +++ b/JmeTests/src/jme3test/collision/TestRayCasting.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.collision; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingSphere; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.scene.Mesh; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer.Type; + +public class TestRayCasting extends SimpleApplication { + + private RayTrace tracer; + private Spatial teapot; + + public static void main(String[] args){ + TestRayCasting app = new TestRayCasting(); + app.setPauseOnLostFocus(false); + app.start(); + } + + @Override + public void simpleInitApp() { +// flyCam.setEnabled(false); + + // load material + Material mat = (Material) assetManager.loadMaterial("Interface/Logo/Logo.j3m"); + + Mesh q = new Mesh(); + q.setBuffer(Type.Position, 3, new float[] + { + 1, 0, 0, + 0, 1.5f, 0, + -1, 0, 0 + } + ); + q.setBuffer(Type.Index, 3, new int[]{ 0, 1, 2 }); + q.setBound(new BoundingSphere()); + q.updateBound(); +// Geometry teapot = new Geometry("MyGeom", q); + + teapot = assetManager.loadModel("Models/Teapot/Teapot.mesh.xml"); +// teapot.scale(2f, 2f, 2f); +// teapot.move(2f, 2f, -.5f); + teapot.rotate(FastMath.HALF_PI, FastMath.HALF_PI, FastMath.HALF_PI); + teapot.setMaterial(mat); + rootNode.attachChild(teapot); + +// cam.setLocation(cam.getLocation().add(0,1,0)); +// cam.lookAt(teapot.getWorldBound().getCenter(), Vector3f.UNIT_Y); + + tracer = new RayTrace(rootNode, cam, 160, 128); + tracer.show(); + tracer.update(); + } + + @Override + public void simpleUpdate(float tpf){ + teapot.rotate(0,tpf,0); + tracer.update(); + } + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/collision/TestTriangleCollision.java b/JmeTests/src/jme3test/collision/TestTriangleCollision.java new file mode 100644 index 0000000..e28d7c7 --- /dev/null +++ b/JmeTests/src/jme3test/collision/TestTriangleCollision.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.collision; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingVolume; +import com.jme3.collision.CollisionResults; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; + +public class TestTriangleCollision extends SimpleApplication { + + Geometry geom1; + + Spatial golem; + + public static void main(String[] args) { + TestTriangleCollision app = new TestTriangleCollision(); + app.start(); + } + + @Override + public void simpleInitApp() { + // Create two boxes + Mesh mesh1 = new Box(0.5f, 0.5f, 0.5f); + geom1 = new Geometry("Box", mesh1); + geom1.move(2, 2, -.5f); + Material m1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m1.setColor("Color", ColorRGBA.Blue); + geom1.setMaterial(m1); + rootNode.attachChild(geom1); + + // load a character from jme3test-test-data + golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + golem.scale(0.5f); + golem.setLocalTranslation(-1.0f, -1.5f, -0.6f); + + // We must add a light to make the model visible + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal()); + golem.addLight(sun); + rootNode.attachChild(golem); + + // Create input + inputManager.addMapping("MoveRight", new KeyTrigger(KeyInput.KEY_L)); + inputManager.addMapping("MoveLeft", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("MoveUp", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addMapping("MoveDown", new KeyTrigger(KeyInput.KEY_K)); + + inputManager.addListener(analogListener, new String[]{ + "MoveRight", "MoveLeft", "MoveUp", "MoveDown" + }); + } + private AnalogListener analogListener = new AnalogListener() { + + public void onAnalog(String name, float value, float tpf) { + if (name.equals("MoveRight")) { + geom1.move(2 * tpf, 0, 0); + } + + if (name.equals("MoveLeft")) { + geom1.move(-2 * tpf, 0, 0); + } + + if (name.equals("MoveUp")) { + geom1.move(0, 2 * tpf, 0); + } + + if (name.equals("MoveDown")) { + geom1.move(0, -2 * tpf, 0); + } + } + }; + + @Override + public void simpleUpdate(float tpf) { + CollisionResults results = new CollisionResults(); + BoundingVolume bv = geom1.getWorldBound(); + golem.collideWith(bv, results); + + if (results.size() > 0) { + geom1.getMaterial().setColor("Color", ColorRGBA.Red); + }else{ + geom1.getMaterial().setColor("Color", ColorRGBA.Blue); + } + } +} diff --git a/JmeTests/src/jme3test/conversion/TestMipMapGen.java b/JmeTests/src/jme3test/conversion/TestMipMapGen.java new file mode 100644 index 0000000..6110469 --- /dev/null +++ b/JmeTests/src/jme3test/conversion/TestMipMapGen.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.conversion; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.util.MipMapGenerator; + +public class TestMipMapGen extends SimpleApplication { + + public static void main(String[] args){ + TestMipMapGen app = new TestMipMapGen(); + app.start(); + } + + @Override + public void simpleInitApp() { + BitmapText txt = guiFont.createLabel("Left: HW Mips"); + txt.setLocalTranslation(0, settings.getHeight() - txt.getLineHeight() * 4, 0); + guiNode.attachChild(txt); + + txt = guiFont.createLabel("Right: AWT Mips"); + txt.setLocalTranslation(0, settings.getHeight() - txt.getLineHeight() * 3, 0); + guiNode.attachChild(txt); + + // create a simple plane/quad + Quad quadMesh = new Quad(1, 1); + quadMesh.updateGeometry(1, 1, false); + quadMesh.updateBound(); + + Geometry quad1 = new Geometry("Textured Quad", quadMesh); + Geometry quad2 = new Geometry("Textured Quad 2", quadMesh); + + Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.png"); + tex.setMinFilter(Texture.MinFilter.Trilinear); + + Texture texCustomMip = tex.clone(); + Image imageCustomMip = texCustomMip.getImage().clone(); + MipMapGenerator.generateMipMaps(imageCustomMip); + texCustomMip.setImage(imageCustomMip); + + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setTexture("ColorMap", tex); + + Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setTexture("ColorMap", texCustomMip); + + quad1.setMaterial(mat1); +// quad1.setLocalTranslation(1, 0, 0); + + quad2.setMaterial(mat2); + quad2.setLocalTranslation(1, 0, 0); + + rootNode.attachChild(quad1); + rootNode.attachChild(quad2); + } + +} diff --git a/JmeTests/src/jme3test/effect/TestEverything.java b/JmeTests/src/jme3test/effect/TestEverything.java new file mode 100644 index 0000000..62f06a4 --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestEverything.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.renderer.Caps; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.scene.shape.Box; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import com.jme3.util.TangentBinormalGenerator; + +public class TestEverything extends SimpleApplication { + + private DirectionalLightShadowRenderer dlsr; + private ToneMapFilter toneMapFilter; + private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); + + public static void main(String[] args){ + TestEverything app = new TestEverything(); + app.start(); + } + + public void setupHdr(){ + if (renderer.getCaps().contains(Caps.GLSL100)){ + toneMapFilter = new ToneMapFilter(); + toneMapFilter.setWhitePoint(new Vector3f(3f, 3f, 3f)); + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(toneMapFilter); + viewPort.addProcessor(fpp); + + // setPauseOnLostFocus(false); + } + } + + public void setupBasicShadow(){ + if (renderer.getCaps().contains(Caps.GLSL100)){ + dlsr = new DirectionalLightShadowRenderer(assetManager, 1024, 1); + viewPort.addProcessor(dlsr); + } + } + + public void setupSkyBox(){ + Texture envMap; + if (renderer.getCaps().contains(Caps.FloatTexture)){ + envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.hdr"); + }else{ + envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.jpg"); + } + rootNode.attachChild(SkyFactory.createSky(assetManager, envMap, + new Vector3f(-1,-1,-1), SkyFactory.EnvMapType.SphereMap)); + } + + public void setupLighting(){ + boolean hdr = false; + if (toneMapFilter != null){ + hdr = toneMapFilter.isEnabled(); + } + + DirectionalLight dl = new DirectionalLight(); + if (dlsr != null) { + dlsr.setLight(dl); + } + dl.setDirection(lightDir); + if (hdr){ + dl.setColor(new ColorRGBA(3, 3, 3, 1)); + }else{ + dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1)); + } + rootNode.addLight(dl); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, 0, -1).normalizeLocal()); + if (hdr){ + dl.setColor(new ColorRGBA(1, 1, 1, 1)); + }else{ + dl.setColor(new ColorRGBA(.4f, .4f, .4f, 1)); + } + rootNode.addLight(dl); + } + + public void setupFloor(){ + Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); + Box floor = new Box(50, 1f, 50); + TangentBinormalGenerator.generate(floor); + floor.scaleTextureCoordinates(new Vector2f(5, 5)); + Geometry floorGeom = new Geometry("Floor", floor); + floorGeom.setMaterial(mat); + floorGeom.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(floorGeom); + } + +// public void setupTerrain(){ +// Material mat = manager.loadMaterial("Textures/Terrain/Rock/Rock.j3m"); +// mat.getTextureParam("DiffuseMap").getValue().setWrap(WrapMode.Repeat); +// mat.getTextureParam("NormalMap").getValue().setWrap(WrapMode.Repeat); +// try{ +// Geomap map = GeomapLoader.fromImage(TestEverything.class.getResource("/textures/heightmap.png")); +// Mesh m = map.createMesh(new Vector3f(0.35f, 0.0005f, 0.35f), new Vector2f(10, 10), true); +// Logger.getLogger(TangentBinormalGenerator.class.getName()).setLevel(Level.SEVERE); +// TangentBinormalGenerator.generate(m); +// Geometry t = new Geometry("Terrain", m); +// t.setLocalTranslation(85, -15, 0); +// t.setMaterial(mat); +// t.updateModelBound(); +// t.setShadowMode(ShadowMode.Receive); +// rootNode.attachChild(t); +// }catch (IOException ex){ +// ex.printStackTrace(); +// } +// +// } + + public void setupRobotGuy(){ + Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Oto/Oto.j3m"); + model.getChild(0).setMaterial(mat); +// model.setAnimation("Walk"); + model.setLocalTranslation(30, 10.5f, 30); + model.setLocalScale(2); + model.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(model); + } + + public void setupSignpost(){ + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + signpost.setMaterial(mat); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 3.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(-32.295086f, 54.80136f, 79.59805f)); + cam.setRotation(new Quaternion(0.074364014f, 0.92519957f, -0.24794696f, 0.27748522f)); + cam.update(); + + cam.setFrustumFar(300); + flyCam.setMoveSpeed(30); + + rootNode.setCullHint(CullHint.Never); + + setupBasicShadow(); + setupHdr(); + + setupLighting(); + setupSkyBox(); + +// setupTerrain(); + setupFloor(); +// setupRobotGuy(); + setupSignpost(); + + + } + +} diff --git a/JmeTests/src/jme3test/effect/TestExplosionEffect.java b/JmeTests/src/jme3test/effect/TestExplosionEffect.java new file mode 100644 index 0000000..ff5100f --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestExplosionEffect.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +public class TestExplosionEffect extends SimpleApplication { + + private float time = 0; + private int state = 0; + private Node explosionEffect = new Node("explosionFX"); + private ParticleEmitter flame, flash, spark, roundspark, smoketrail, debris, + shockwave; + + + private static final int COUNT_FACTOR = 1; + private static final float COUNT_FACTOR_F = 1f; + + private static final boolean POINT_SPRITE = true; + private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle; + + public static void main(String[] args){ + TestExplosionEffect app = new TestExplosionEffect(); + app.start(); + } + + private void createFlame(){ + flame = new ParticleEmitter("Flame", EMITTER_TYPE, 32 * COUNT_FACTOR); + flame.setSelectRandomImage(true); + flame.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F))); + flame.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f)); + flame.setStartSize(1.3f); + flame.setEndSize(2f); + flame.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); + flame.setParticlesPerSec(0); + flame.setGravity(0, -5, 0); + flame.setLowLife(.4f); + flame.setHighLife(.5f); + flame.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 7, 0)); + flame.getParticleInfluencer().setVelocityVariation(1f); + flame.setImagesX(2); + flame.setImagesY(2); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + mat.setBoolean("PointSprite", POINT_SPRITE); + flame.setMaterial(mat); + explosionEffect.attachChild(flame); + } + + private void createFlash(){ + flash = new ParticleEmitter("Flash", EMITTER_TYPE, 24 * COUNT_FACTOR); + flash.setSelectRandomImage(true); + flash.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1f / COUNT_FACTOR_F))); + flash.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f)); + flash.setStartSize(.1f); + flash.setEndSize(3.0f); + flash.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f)); + flash.setParticlesPerSec(0); + flash.setGravity(0, 0, 0); + flash.setLowLife(.2f); + flash.setHighLife(.2f); + flash.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 5f, 0)); + flash.getParticleInfluencer().setVelocityVariation(1); + flash.setImagesX(2); + flash.setImagesY(2); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flash.png")); + mat.setBoolean("PointSprite", POINT_SPRITE); + flash.setMaterial(mat); + explosionEffect.attachChild(flash); + } + + private void createRoundSpark(){ + roundspark = new ParticleEmitter("RoundSpark", EMITTER_TYPE, 20 * COUNT_FACTOR); + roundspark.setStartColor(new ColorRGBA(1f, 0.29f, 0.34f, (float) (1.0 / COUNT_FACTOR_F))); + roundspark.setEndColor(new ColorRGBA(0, 0, 0, (float) (0.5f / COUNT_FACTOR_F))); + roundspark.setStartSize(1.2f); + roundspark.setEndSize(1.8f); + roundspark.setShape(new EmitterSphereShape(Vector3f.ZERO, 2f)); + roundspark.setParticlesPerSec(0); + roundspark.setGravity(0, -.5f, 0); + roundspark.setLowLife(1.8f); + roundspark.setHighLife(2f); + roundspark.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 3, 0)); + roundspark.getParticleInfluencer().setVelocityVariation(.5f); + roundspark.setImagesX(1); + roundspark.setImagesY(1); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/roundspark.png")); + mat.setBoolean("PointSprite", POINT_SPRITE); + roundspark.setMaterial(mat); + explosionEffect.attachChild(roundspark); + } + + private void createSpark(){ + spark = new ParticleEmitter("Spark", Type.Triangle, 30 * COUNT_FACTOR); + spark.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1.0f / COUNT_FACTOR_F))); + spark.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f)); + spark.setStartSize(.5f); + spark.setEndSize(.5f); + spark.setFacingVelocity(true); + spark.setParticlesPerSec(0); + spark.setGravity(0, 5, 0); + spark.setLowLife(1.1f); + spark.setHighLife(1.5f); + spark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 20, 0)); + spark.getParticleInfluencer().setVelocityVariation(1); + spark.setImagesX(1); + spark.setImagesY(1); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/spark.png")); + spark.setMaterial(mat); + explosionEffect.attachChild(spark); + } + + private void createSmokeTrail(){ + smoketrail = new ParticleEmitter("SmokeTrail", Type.Triangle, 22 * COUNT_FACTOR); + smoketrail.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1.0f / COUNT_FACTOR_F))); + smoketrail.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f)); + smoketrail.setStartSize(.2f); + smoketrail.setEndSize(1f); + +// smoketrail.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); + smoketrail.setFacingVelocity(true); + smoketrail.setParticlesPerSec(0); + smoketrail.setGravity(0, 1, 0); + smoketrail.setLowLife(.4f); + smoketrail.setHighLife(.5f); + smoketrail.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 12, 0)); + smoketrail.getParticleInfluencer().setVelocityVariation(1); + smoketrail.setImagesX(1); + smoketrail.setImagesY(3); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/smoketrail.png")); + smoketrail.setMaterial(mat); + explosionEffect.attachChild(smoketrail); + } + + private void createDebris(){ + debris = new ParticleEmitter("Debris", Type.Triangle, 15 * COUNT_FACTOR); + debris.setSelectRandomImage(true); + debris.setRandomAngle(true); + debris.setRotateSpeed(FastMath.TWO_PI * 4); + debris.setStartColor(new ColorRGBA(1f, 0.59f, 0.28f, (float) (1.0f / COUNT_FACTOR_F))); + debris.setEndColor(new ColorRGBA(.5f, 0.5f, 0.5f, 0f)); + debris.setStartSize(.2f); + debris.setEndSize(.2f); + +// debris.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f)); + debris.setParticlesPerSec(0); + debris.setGravity(0, 12f, 0); + debris.setLowLife(1.4f); + debris.setHighLife(1.5f); + debris.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 15, 0)); + debris.getParticleInfluencer().setVelocityVariation(.60f); + debris.setImagesX(3); + debris.setImagesY(3); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/Debris.png")); + debris.setMaterial(mat); + explosionEffect.attachChild(debris); + } + + private void createShockwave(){ + shockwave = new ParticleEmitter("Shockwave", Type.Triangle, 1 * COUNT_FACTOR); +// shockwave.setRandomAngle(true); + shockwave.setFaceNormal(Vector3f.UNIT_Y); + shockwave.setStartColor(new ColorRGBA(.48f, 0.17f, 0.01f, (float) (.8f / COUNT_FACTOR_F))); + shockwave.setEndColor(new ColorRGBA(.48f, 0.17f, 0.01f, 0f)); + + shockwave.setStartSize(0f); + shockwave.setEndSize(7f); + + shockwave.setParticlesPerSec(0); + shockwave.setGravity(0, 0, 0); + shockwave.setLowLife(0.5f); + shockwave.setHighLife(0.5f); + shockwave.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, 0, 0)); + shockwave.getParticleInfluencer().setVelocityVariation(0f); + shockwave.setImagesX(1); + shockwave.setImagesY(1); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/shockwave.png")); + shockwave.setMaterial(mat); + explosionEffect.attachChild(shockwave); + } + + @Override + public void simpleInitApp() { + createFlame(); + createFlash(); + createSpark(); + createRoundSpark(); + createSmokeTrail(); + createDebris(); + createShockwave(); + explosionEffect.setLocalScale(0.5f); + renderManager.preloadScene(explosionEffect); + + cam.setLocation(new Vector3f(0, 3.5135868f, 10)); + cam.setRotation(new Quaternion(1.5714673E-4f, 0.98696727f, -0.16091813f, 9.6381607E-4f)); + + rootNode.attachChild(explosionEffect); + } + + @Override + public void simpleUpdate(float tpf){ + time += tpf / speed; + if (time > 1f && state == 0){ + flash.emitAllParticles(); + spark.emitAllParticles(); + smoketrail.emitAllParticles(); + debris.emitAllParticles(); + shockwave.emitAllParticles(); + state++; + } + if (time > 1f + .05f / speed && state == 1){ + flame.emitAllParticles(); + roundspark.emitAllParticles(); + state++; + } + + // rewind the effect + if (time > 5 / speed && state == 2){ + state = 0; + time = 0; + + flash.killAllParticles(); + spark.killAllParticles(); + smoketrail.killAllParticles(); + debris.killAllParticles(); + flame.killAllParticles(); + roundspark.killAllParticles(); + shockwave.killAllParticles(); + } + } + +} diff --git a/JmeTests/src/jme3test/effect/TestMovingParticle.java b/JmeTests/src/jme3test/effect/TestMovingParticle.java new file mode 100644 index 0000000..b38eed9 --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestMovingParticle.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; + +/** + * Particle that moves in a circle. + * + * @author Kirill Vainer + */ +public class TestMovingParticle extends SimpleApplication { + + private ParticleEmitter emit; + private float angle = 0; + + public static void main(String[] args) { + TestMovingParticle app = new TestMovingParticle(); + app.start(); + } + + @Override + public void simpleInitApp() { + emit = new ParticleEmitter("Emitter", Type.Triangle, 300); + emit.setGravity(0, 0, 0); + emit.getParticleInfluencer().setVelocityVariation(1); + emit.setLowLife(1); + emit.setHighLife(1); + emit.getParticleInfluencer() + .setInitialVelocity(new Vector3f(0, .5f, 0)); + emit.setImagesX(15); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png")); + emit.setMaterial(mat); + + rootNode.attachChild(emit); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if ("setNum".equals(name) && isPressed) { + emit.setNumParticles(1000); + } + } + }, "setNum"); + + inputManager.addMapping("setNum", new KeyTrigger(KeyInput.KEY_SPACE)); + } + + @Override + public void simpleUpdate(float tpf) { + angle += tpf; + angle %= FastMath.TWO_PI; + float x = FastMath.cos(angle) * 2; + float y = FastMath.sin(angle) * 2; + emit.setLocalTranslation(x, 0, y); + } +} diff --git a/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java b/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java new file mode 100644 index 0000000..d38fdbd --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.export.binary.BinaryImporter; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class TestParticleExportingCloning extends SimpleApplication { + + public static void main(String[] args){ + TestParticleExportingCloning app = new TestParticleExportingCloning(); + app.start(); + } + + @Override + public void simpleInitApp() { + ParticleEmitter emit = new ParticleEmitter("Emitter", Type.Triangle, 200); + emit.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f)); + emit.setGravity(0, 0, 0); + emit.setLowLife(5); + emit.setHighLife(10); + emit.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0)); + emit.setImagesX(15); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png")); + emit.setMaterial(mat); + + ParticleEmitter emit2 = emit.clone(); + emit2.move(3, 0, 0); + + rootNode.attachChild(emit); + rootNode.attachChild(emit2); + + ParticleEmitter emit3 = BinaryExporter.saveAndLoad(assetManager, emit); + emit3.move(-3, 0, 0); + rootNode.attachChild(emit3); + } + +} diff --git a/JmeTests/src/jme3test/effect/TestPointSprite.java b/JmeTests/src/jme3test/effect/TestPointSprite.java new file mode 100644 index 0000000..1a3e890 --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestPointSprite.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.shapes.EmitterBoxShape; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; + +public class TestPointSprite extends SimpleApplication { + + public static void main(String[] args){ + TestPointSprite app = new TestPointSprite(); + app.start(); + } + + @Override + public void simpleInitApp() { + final ParticleEmitter emit = new ParticleEmitter("Emitter", Type.Point, 10000); + emit.setShape(new EmitterBoxShape(new Vector3f(-1.8f, -1.8f, -1.8f), + new Vector3f(1.8f, 1.8f, 1.8f))); + emit.setGravity(0, 0, 0); + emit.setLowLife(60); + emit.setHighLife(60); + emit.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0)); + emit.setImagesX(15); + emit.setStartSize(0.05f); + emit.setEndSize(0.05f); + emit.setStartColor(ColorRGBA.White); + emit.setEndColor(ColorRGBA.White); + emit.setSelectRandomImage(true); + emit.emitAllParticles(); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat.setBoolean("PointSprite", true); + mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png")); + emit.setMaterial(mat); + + rootNode.attachChild(emit); + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if ("setNum".equals(name) && isPressed) { + emit.setNumParticles(5000); + emit.emitAllParticles(); + } + } + }, "setNum"); + + inputManager.addMapping("setNum", new KeyTrigger(KeyInput.KEY_SPACE)); + + } + +} diff --git a/JmeTests/src/jme3test/effect/TestSoftParticles.java b/JmeTests/src/jme3test/effect/TestSoftParticles.java new file mode 100644 index 0000000..84189e1 --- /dev/null +++ b/JmeTests/src/jme3test/effect/TestSoftParticles.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.effect; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.effect.shapes.EmitterSphereShape; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.TranslucentBucketFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; + +/** + * + * @author Nehon + */ +public class TestSoftParticles extends SimpleApplication { + + private boolean softParticles = true; + private FilterPostProcessor fpp; + private TranslucentBucketFilter tbf; + private Node particleNode; + + public static void main(String[] args) { + TestSoftParticles app = new TestSoftParticles(); + app.start(); + } + + @Override + public void simpleInitApp() { + + cam.setLocation(new Vector3f(-7.2221026f, 4.1183004f, 7.759811f)); + cam.setRotation(new Quaternion(0.06152846f, 0.91236454f, -0.1492115f, 0.37621948f)); + + flyCam.setMoveSpeed(10); + + + // -------- floor + Box b = new Box(10, 0.1f, 10); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Gray); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + Box b2 = new Box(1, 1, 1); + Geometry geom2 = new Geometry("Box", b2); + Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setColor("Color", ColorRGBA.DarkGray); + geom2.setMaterial(mat2); + rootNode.attachChild(geom2); + geom2.setLocalScale(0.1f, 0.2f, 1); + + fpp = new FilterPostProcessor(assetManager); + tbf = new TranslucentBucketFilter(true); + fpp.addFilter(tbf); + int samples = context.getSettings().getSamples(); + if (samples > 0) { + fpp.setNumSamples(samples); + } + viewPort.addProcessor(fpp); + + particleNode = new Node("particleNode"); + rootNode.attachChild(particleNode); + + createParticles(); + + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed && name.equals("toggle")){ + // tbf.setEnabled(!tbf.isEnabled()); + softParticles = !softParticles; + if(softParticles){ + viewPort.addProcessor(fpp); + }else{ + viewPort.removeProcessor(fpp); + } + } + } + }, "toggle"); + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + // emit again + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed && name.equals("refire")) { + //fpp.removeFilter(tbf); // <-- add back in to fix + particleNode.detachAllChildren(); + createParticles(); + //fpp.addFilter(tbf); + } + } + }, "refire"); + inputManager.addMapping("refire", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + } + + private void createParticles() { + + Material material = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + material.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + material.setFloat("Softness", 3f); // + + //Fire + ParticleEmitter fire = new ParticleEmitter("Fire", ParticleMesh.Type.Triangle, 30); + fire.setMaterial(material); + fire.setShape(new EmitterSphereShape(Vector3f.ZERO, 0.1f)); + fire.setImagesX(2); + fire.setImagesY(2); // 2x2 texture animation + fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red + fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow + fire.setStartSize(0.6f); + fire.setEndSize(0.01f); + fire.setGravity(0, -0.3f, 0); + fire.setLowLife(0.5f); + fire.setHighLife(3f); + fire.setLocalTranslation(0, 0.2f, 0); + + particleNode.attachChild(fire); + + + ParticleEmitter smoke = new ParticleEmitter("Smoke", ParticleMesh.Type.Triangle, 30); + smoke.setMaterial(material); + smoke.setShape(new EmitterSphereShape(Vector3f.ZERO, 5)); + smoke.setImagesX(1); + smoke.setImagesY(1); // 2x2 texture animation + smoke.setStartColor(new ColorRGBA(0.1f, 0.1f, 0.1f,1f)); // dark gray + smoke.setEndColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.3f)); // gray + smoke.setStartSize(3f); + smoke.setEndSize(5f); + smoke.setGravity(0, -0.001f, 0); + smoke.setLowLife(100f); + smoke.setHighLife(100f); + smoke.setLocalTranslation(0, 0.1f, 0); + smoke.emitAllParticles(); + + particleNode.attachChild(smoke); + } + + +} diff --git a/JmeTests/src/jme3test/export/TestAssetLinkNode.java b/JmeTests/src/jme3test/export/TestAssetLinkNode.java new file mode 100644 index 0000000..d2c7213 --- /dev/null +++ b/JmeTests/src/jme3test/export/TestAssetLinkNode.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.export; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.AssetKey; +import com.jme3.asset.ModelKey; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.export.binary.BinaryImporter; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestAssetLinkNode extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args){ + TestAssetLinkNode app = new TestAssetLinkNode(); + app.start(); + } + + @Override + public void simpleInitApp() { + AssetLinkNode loaderNode=new AssetLinkNode(); + loaderNode.addLinkedChild(new ModelKey("Models/MonkeyHead/MonkeyHead.mesh.xml")); + //load/attach the children (happens automatically on load) +// loaderNode.attachLinkedChildren(assetManager); +// rootNode.attachChild(loaderNode); + + //save and load the loaderNode + try { + //export to byte array + ByteArrayOutputStream bout=new ByteArrayOutputStream(); + BinaryExporter.getInstance().save(loaderNode, bout); + //import from byte array, automatically loads the monkeyhead from file + ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray()); + BinaryImporter imp=BinaryImporter.getInstance(); + imp.setAssetManager(assetManager); + Node newLoaderNode=(Node)imp.load(bin); + //attach to rootNode + rootNode.attachChild(newLoaderNode); + } catch (IOException ex) { + Logger.getLogger(TestAssetLinkNode.class.getName()).log(Level.SEVERE, null, ex); + } + + + rootNode.attachChild(loaderNode); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial( (Material) assetManager.loadAsset(new AssetKey("Common/Materials/RedColor.j3m"))); + rootNode.attachChild(lightMdl); + + // flourescent main light + pl = new PointLight(); + pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f)); + rootNode.addLight(pl); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f)); + rootNode.addLight(dl); + + // skylight + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f)); + rootNode.addLight(dl); + + // white ambient light + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf * 0.25f; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/export/TestOgreConvert.java b/JmeTests/src/jme3test/export/TestOgreConvert.java new file mode 100644 index 0000000..bfc03c0 --- /dev/null +++ b/JmeTests/src/jme3test/export/TestOgreConvert.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.export; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.export.binary.BinaryImporter; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class TestOgreConvert extends SimpleApplication { + + public static void main(String[] args){ + TestOgreConvert app = new TestOgreConvert(); + app.start(); + } + + @Override + public void simpleInitApp() { + Spatial ogreModel = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White); + dl.setDirection(new Vector3f(0,-1,-1).normalizeLocal()); + rootNode.addLight(dl); + + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryExporter exp = new BinaryExporter(); + exp.save(ogreModel, baos); + + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + BinaryImporter imp = new BinaryImporter(); + imp.setAssetManager(assetManager); + Node ogreModelReloaded = (Node) imp.load(bais, null, null); + + AnimControl control = ogreModelReloaded.getControl(AnimControl.class); + AnimChannel chan = control.createChannel(); + chan.setAnim("Walk"); + + rootNode.attachChild(ogreModelReloaded); + } catch (IOException ex){ + ex.printStackTrace(); + } + } +} diff --git a/JmeTests/src/jme3test/games/CubeField.java b/JmeTests/src/jme3test/games/CubeField.java new file mode 100644 index 0000000..c166b58 --- /dev/null +++ b/JmeTests/src/jme3test/games/CubeField.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.games; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingVolume; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Dome; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Kyle "bonechilla" Williams + */ +public class CubeField extends SimpleApplication implements AnalogListener { + + public static void main(String[] args) { + CubeField app = new CubeField(); + app.start(); + } + + private BitmapFont defaultFont; + + private boolean START; + private int difficulty, Score, colorInt, highCap, lowCap,diffHelp; + private Node player; + private Geometry fcube; + private ArrayList cubeField; + private ArrayList obstacleColors; + private float speed, coreTime,coreTime2; + private float camAngle = 0; + private BitmapText fpsScoreText, pressStart; + + private boolean solidBox = true; + private Material playerMaterial; + private Material floorMaterial; + + private float fpsRate = 1000f / 1f; + + /** + * Initializes game + */ + @Override + public void simpleInitApp() { + Logger.getLogger("com.jme3").setLevel(Level.WARNING); + + flyCam.setEnabled(false); + setDisplayStatView(false); + + Keys(); + + defaultFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + pressStart = new BitmapText(defaultFont, false); + fpsScoreText = new BitmapText(defaultFont, false); + + loadText(fpsScoreText, "Current Score: 0", defaultFont, 0, 2, 0); + loadText(pressStart, "PRESS ENTER", defaultFont, 0, 5, 0); + + player = createPlayer(); + rootNode.attachChild(player); + cubeField = new ArrayList(); + obstacleColors = new ArrayList(); + + gameReset(); + } + /** + * Used to reset cubeField + */ + private void gameReset(){ + Score = 0; + lowCap = 10; + colorInt = 0; + highCap = 40; + difficulty = highCap; + + for (Geometry cube : cubeField){ + cube.removeFromParent(); + } + cubeField.clear(); + + if (fcube != null){ + fcube.removeFromParent(); + } + fcube = createFirstCube(); + + obstacleColors.clear(); + obstacleColors.add(ColorRGBA.Orange); + obstacleColors.add(ColorRGBA.Red); + obstacleColors.add(ColorRGBA.Yellow); + renderer.setBackgroundColor(ColorRGBA.White); + speed = lowCap / 400f; + coreTime = 20.0f; + coreTime2 = 10.0f; + diffHelp=lowCap; + player.setLocalTranslation(0,0,0); + } + + @Override + public void simpleUpdate(float tpf) { + camTakeOver(tpf); + if (START){ + gameLogic(tpf); + } + colorLogic(); + } + /** + * Forcefully takes over Camera adding functionality and placing it behind the character + * @param tpf Tickes Per Frame + */ + private void camTakeOver(float tpf) { + cam.setLocation(player.getLocalTranslation().add(-8, 2, 0)); + cam.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y); + + Quaternion rot = new Quaternion(); + rot.fromAngleNormalAxis(camAngle, Vector3f.UNIT_Z); + cam.setRotation(cam.getRotation().mult(rot)); + camAngle *= FastMath.pow(.99f, fpsRate * tpf); + } + + @Override + public void requestClose(boolean esc) { + if (!esc){ + System.out.println("The game was quit."); + }else{ + System.out.println("Player has Collided. Final Score is " + Score); + } + context.destroy(false); + } + /** + * Randomly Places a cube on the map between 30 and 90 paces away from player + */ + private void randomizeCube() { + Geometry cube = fcube.clone(); + int playerX = (int) player.getLocalTranslation().getX(); + int playerZ = (int) player.getLocalTranslation().getZ(); +// float x = FastMath.nextRandomInt(playerX + difficulty + 10, playerX + difficulty + 150); + float x = FastMath.nextRandomInt(playerX + difficulty + 30, playerX + difficulty + 90); + float z = FastMath.nextRandomInt(playerZ - difficulty - 50, playerZ + difficulty + 50); + cube.getLocalTranslation().set(x, 0, z); + +// playerX+difficulty+30,playerX+difficulty+90 + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + if (!solidBox){ + mat.getAdditionalRenderState().setWireframe(true); + } + mat.setColor("Color", obstacleColors.get(FastMath.nextRandomInt(0, obstacleColors.size() - 1))); + cube.setMaterial(mat); + + rootNode.attachChild(cube); + cubeField.add(cube); + } + + private Geometry createFirstCube() { + Vector3f loc = player.getLocalTranslation(); + loc.addLocal(4, 0, 0); + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + geom.setLocalTranslation(loc); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + geom.setMaterial(mat); + + return geom; + } + + private Node createPlayer() { + Dome b = new Dome(Vector3f.ZERO, 10, 100, 1); + Geometry playerMesh = new Geometry("Box", b); + + playerMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + playerMaterial.setColor("Color", ColorRGBA.Red); + playerMesh.setMaterial(playerMaterial); + playerMesh.setName("player"); + + Box floor = new Box(100, 0, 100); + + Geometry floorMesh = new Geometry("Box", floor); + + Vector3f translation = Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(), + playerMesh.getLocalTranslation().getY() - 1, 0); + + floorMesh.setLocalTranslation(translation); + + floorMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + floorMaterial.setColor("Color", ColorRGBA.LightGray); + floorMesh.setMaterial(floorMaterial); + floorMesh.setName("floor"); + + Node playerNode = new Node(); + playerNode.attachChild(playerMesh); + playerNode.attachChild(floorMesh); + + return playerNode; + } + + /** + * If Game is Lost display Score and Reset the Game + */ + private void gameLost(){ + START = false; + loadText(pressStart, "You lost! Press enter to try again.", defaultFont, 0, 5, 0); + gameReset(); + } + + /** + * Core Game Logic + */ + private void gameLogic(float tpf){ + //Subtract difficulty level in accordance to speed every 10 seconds + if(timer.getTimeInSeconds()>=coreTime2){ + coreTime2=timer.getTimeInSeconds()+10; + if(difficulty<=lowCap){ + difficulty=lowCap; + } + else if(difficulty>lowCap){ + difficulty-=5; + diffHelp+=1; + } + } + + if(speed<.1f){ + speed+=.000001f*tpf*fpsRate; + } + + player.move(speed * tpf * fpsRate, 0, 0); + if (cubeField.size() > difficulty){ + cubeField.remove(0); + }else if (cubeField.size() != difficulty){ + randomizeCube(); + } + + if (cubeField.isEmpty()){ + requestClose(false); + }else{ + for (int i = 0; i < cubeField.size(); i++){ + + //better way to check collision + Geometry playerModel = (Geometry) player.getChild(0); + Geometry cubeModel = cubeField.get(i); + cubeModel.updateGeometricState(); + + BoundingVolume pVol = playerModel.getWorldBound(); + BoundingVolume vVol = cubeModel.getWorldBound(); + + if (pVol.intersects(vVol)){ + gameLost(); + return; + } + //Remove cube if 10 world units behind player + if (cubeField.get(i).getLocalTranslation().getX() + 10 < player.getLocalTranslation().getX()){ + cubeField.get(i).removeFromParent(); + cubeField.remove(cubeField.get(i)); + } + + } + } + + Score += fpsRate * tpf; + fpsScoreText.setText("Current Score: "+Score); + } + /** + * Sets up the keyboard bindings + */ + private void Keys() { + inputManager.addMapping("START", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addListener(this, "START", "Left", "Right"); + } + + public void onAnalog(String binding, float value, float tpf) { + if (binding.equals("START") && !START){ + START = true; + guiNode.detachChild(pressStart); + System.out.println("START"); + }else if (START == true && binding.equals("Left")){ + player.move(0, 0, -(speed / 2f) * value * fpsRate); + camAngle -= value*tpf; + }else if (START == true && binding.equals("Right")){ + player.move(0, 0, (speed / 2f) * value * fpsRate); + camAngle += value*tpf; + } + } + + /** + * Determines the colors of the player, floor, obstacle and background + */ + private void colorLogic() { + if (timer.getTimeInSeconds() >= coreTime){ + + colorInt++; + coreTime = timer.getTimeInSeconds() + 20; + + + switch (colorInt){ + case 1: + obstacleColors.clear(); + solidBox = false; + obstacleColors.add(ColorRGBA.Green); + renderer.setBackgroundColor(ColorRGBA.Black); + playerMaterial.setColor("Color", ColorRGBA.White); + floorMaterial.setColor("Color", ColorRGBA.Black); + break; + case 2: + obstacleColors.set(0, ColorRGBA.Black); + solidBox = true; + renderer.setBackgroundColor(ColorRGBA.White); + playerMaterial.setColor("Color", ColorRGBA.Gray); + floorMaterial.setColor("Color", ColorRGBA.LightGray); + break; + case 3: + obstacleColors.set(0, ColorRGBA.Pink); + break; + case 4: + obstacleColors.set(0, ColorRGBA.Cyan); + obstacleColors.add(ColorRGBA.Magenta); + renderer.setBackgroundColor(ColorRGBA.Gray); + floorMaterial.setColor("Color", ColorRGBA.Gray); + playerMaterial.setColor("Color", ColorRGBA.White); + break; + case 5: + obstacleColors.remove(0); + renderer.setBackgroundColor(ColorRGBA.Pink); + solidBox = false; + playerMaterial.setColor("Color", ColorRGBA.White); + break; + case 6: + obstacleColors.set(0, ColorRGBA.White); + solidBox = true; + renderer.setBackgroundColor(ColorRGBA.Black); + playerMaterial.setColor("Color", ColorRGBA.Gray); + floorMaterial.setColor("Color", ColorRGBA.LightGray); + break; + case 7: + obstacleColors.set(0, ColorRGBA.Green); + renderer.setBackgroundColor(ColorRGBA.Gray); + playerMaterial.setColor("Color", ColorRGBA.Black); + floorMaterial.setColor("Color", ColorRGBA.Orange); + break; + case 8: + obstacleColors.set(0, ColorRGBA.Red); + floorMaterial.setColor("Color", ColorRGBA.Pink); + break; + case 9: + obstacleColors.set(0, ColorRGBA.Orange); + obstacleColors.add(ColorRGBA.Red); + obstacleColors.add(ColorRGBA.Yellow); + renderer.setBackgroundColor(ColorRGBA.White); + playerMaterial.setColor("Color", ColorRGBA.Red); + floorMaterial.setColor("Color", ColorRGBA.Gray); + colorInt=0; + break; + default: + break; + } + } + } + /** + * Sets up a BitmapText to be displayed + * @param txt the Bitmap Text + * @param text the + * @param font the font of the text + * @param x + * @param y + * @param z + */ + private void loadText(BitmapText txt, String text, BitmapFont font, float x, float y, float z) { + txt.setSize(font.getCharSet().getRenderedSize()); + txt.setLocalTranslation(txt.getLineWidth() * x, txt.getLineHeight() * y, z); + txt.setText(text); + guiNode.attachChild(txt); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/games/RollingTheMonkey.java b/JmeTests/src/jme3test/games/RollingTheMonkey.java new file mode 100644 index 0000000..b349be3 --- /dev/null +++ b/JmeTests/src/jme3test/games/RollingTheMonkey.java @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2009-2017 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.games; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.PhysicsCollisionEvent; +import com.jme3.bullet.collision.PhysicsCollisionListener; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CompoundCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.GhostControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowFilter; +import java.util.concurrent.Callable; + +/** + * Physics based marble game. + * + * @author SkidRunner (Mark E. Picknell) + */ +public class RollingTheMonkey extends SimpleApplication implements ActionListener, PhysicsCollisionListener { + + private static final String TITLE = "Rolling The Monkey"; + private static final String MESSAGE = "Thanks for Playing!"; + private static final String INFO_MESSAGE = "Collect all the spinning cubes!\nPress the 'R' key any time to reset!"; + + private static final float PLAYER_DENSITY = 1200; // OLK(Java LOL) = 1200, STEEL = 8000, RUBBER = 1000 + private static final float PLAYER_REST = 0.1f; // OLK = 0.1f, STEEL = 0.0f, RUBBER = 1.0f I made these up. + + private static final float PLAYER_RADIUS = 2.0f; + private static final float PLAYER_ACCEL = 1.0f; + + private static final float PICKUP_SIZE = 0.5f; + private static final float PICKUP_RADIUS = 15.0f; + private static final int PICKUP_COUNT = 16; + private static final float PICKUP_SPEED = 5.0f; + + private static final float PLAYER_VOLUME = (FastMath.pow(PLAYER_RADIUS, 3) * FastMath.PI) / 3; // V = 4/3 * PI * R pow 3 + private static final float PLAYER_MASS = PLAYER_DENSITY * PLAYER_VOLUME; + private static final float PLAYER_FORCE = 80000 * PLAYER_ACCEL; // F = M(4m diameter steel ball) * A + private static final Vector3f PLAYER_START = new Vector3f(0.0f, PLAYER_RADIUS * 2, 0.0f); + + private static final String INPUT_MAPPING_FORWARD = "INPUT_MAPPING_FORWARD"; + private static final String INPUT_MAPPING_BACKWARD = "INPUT_MAPPING_BACKWARD"; + private static final String INPUT_MAPPING_LEFT = "INPUT_MAPPING_LEFT"; + private static final String INPUT_MAPPING_RIGHT = "INPUT_MAPPING_RIGHT"; + private static final String INPUT_MAPPING_RESET = "INPUT_MAPPING_RESET"; + + public static void main(String[] args) { + RollingTheMonkey app = new RollingTheMonkey(); + app.start(); + } + + private boolean keyForward; + private boolean keyBackward; + private boolean keyLeft; + private boolean keyRight; + + private PhysicsSpace space; + + private RigidBodyControl player; + private int score; + + private Node pickUps; + + BitmapText infoText; + BitmapText scoreText; + BitmapText messageText; + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + cam.setLocation(new Vector3f(0.0f, 12.0f, 21.0f)); + viewPort.setBackgroundColor(new ColorRGBA(0.2118f, 0.0824f, 0.6549f, 1.0f)); + + // init physics + BulletAppState bulletState = new BulletAppState(); + stateManager.attach(bulletState); + space = bulletState.getPhysicsSpace(); + space.addCollisionListener(this); + + // create light + DirectionalLight sun = new DirectionalLight(); + sun.setDirection((new Vector3f(-0.7f, -0.3f, -0.5f)).normalizeLocal()); + System.out.println("Here We Go: " + sun.getDirection()); + sun.setColor(ColorRGBA.White); + rootNode.addLight(sun); + + // create materials + Material materialRed = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + materialRed.setBoolean("UseMaterialColors",true); + materialRed.setBoolean("HardwareShadows", true); + materialRed.setColor("Diffuse", new ColorRGBA(0.9451f, 0.0078f, 0.0314f, 1.0f)); + materialRed.setColor("Specular", ColorRGBA.White); + materialRed.setFloat("Shininess", 64.0f); + + Material materialGreen = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + materialGreen.setBoolean("UseMaterialColors",true); + materialGreen.setBoolean("HardwareShadows", true); + materialGreen.setColor("Diffuse", new ColorRGBA(0.0431f, 0.7725f, 0.0078f, 1.0f)); + materialGreen.setColor("Specular", ColorRGBA.White); + materialGreen.setFloat("Shininess", 64.0f); + + Material logoMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + logoMaterial.setBoolean("UseMaterialColors",true); + logoMaterial.setBoolean("HardwareShadows", true); + logoMaterial.setTexture("DiffuseMap", assetManager.loadTexture("com/jme3/app/Monkey.png")); + logoMaterial.setColor("Diffuse", ColorRGBA.White); + logoMaterial.setColor("Specular", ColorRGBA.White); + logoMaterial.setFloat("Shininess", 32.0f); + + Material materialYellow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + materialYellow.setBoolean("UseMaterialColors",true); + materialYellow.setBoolean("HardwareShadows", true); + materialYellow.setColor("Diffuse", new ColorRGBA(0.9529f, 0.7843f, 0.0078f, 1.0f)); + materialYellow.setColor("Specular", ColorRGBA.White); + materialYellow.setFloat("Shininess", 64.0f); + + // create level spatial + // TODO: create your own level mesh + Node level = new Node("level"); + level.setShadowMode(ShadowMode.CastAndReceive); + + Geometry floor = new Geometry("floor", new Box(22.0f, 0.5f, 22.0f)); + floor.setShadowMode(ShadowMode.Receive); + floor.setLocalTranslation(0.0f, -0.5f, 0.0f); + floor.setMaterial(materialGreen); + + Geometry wallNorth = new Geometry("wallNorth", new Box(22.0f, 2.0f, 0.5f)); + wallNorth.setLocalTranslation(0.0f, 2.0f, 21.5f); + wallNorth.setMaterial(materialRed); + + Geometry wallSouth = new Geometry("wallSouth", new Box(22.0f, 2.0f, 0.5f)); + wallSouth.setLocalTranslation(0.0f, 2.0f, -21.5f); + wallSouth.setMaterial(materialRed); + + Geometry wallEast = new Geometry("wallEast", new Box(0.5f, 2.0f, 21.0f)); + wallEast.setLocalTranslation(-21.5f, 2.0f, 0.0f); + wallEast.setMaterial(materialRed); + + Geometry wallWest = new Geometry("wallWest", new Box(0.5f, 2.0f, 21.0f)); + wallWest.setLocalTranslation(21.5f, 2.0f, 0.0f); + wallWest.setMaterial(materialRed); + + level.attachChild(floor); + level.attachChild(wallNorth); + level.attachChild(wallSouth); + level.attachChild(wallEast); + level.attachChild(wallWest); + + // The easy way: level.addControl(new RigidBodyControl(0)); + + // create level Shape + CompoundCollisionShape levelShape = new CompoundCollisionShape(); + BoxCollisionShape floorShape = new BoxCollisionShape(new Vector3f(22.0f, 0.5f, 22.0f)); + BoxCollisionShape wallNorthShape = new BoxCollisionShape(new Vector3f(22.0f, 2.0f, 0.5f)); + BoxCollisionShape wallSouthShape = new BoxCollisionShape(new Vector3f(22.0f, 2.0f, 0.5f)); + BoxCollisionShape wallEastShape = new BoxCollisionShape(new Vector3f(0.5f, 2.0f, 21.0f)); + BoxCollisionShape wallWestShape = new BoxCollisionShape(new Vector3f(0.5f, 2.0f, 21.0f)); + + levelShape.addChildShape(floorShape, new Vector3f(0.0f, -0.5f, 0.0f)); + levelShape.addChildShape(wallNorthShape, new Vector3f(0.0f, 2.0f, -21.5f)); + levelShape.addChildShape(wallSouthShape, new Vector3f(0.0f, 2.0f, 21.5f)); + levelShape.addChildShape(wallEastShape, new Vector3f(-21.5f, 2.0f, 0.0f)); + levelShape.addChildShape(wallEastShape, new Vector3f(21.5f, 2.0f, 0.0f)); + + level.addControl(new RigidBodyControl(levelShape, 0)); + + rootNode.attachChild(level); + space.addAll(level); + + // create Pickups + // TODO: create your own pickUp mesh + // create single mesh for all pickups + // HINT: think particles. + pickUps = new Node("pickups"); + + Quaternion rotation = new Quaternion(); + Vector3f translation = new Vector3f(0.0f, PICKUP_SIZE * 1.5f, -PICKUP_RADIUS); + int index = 0; + float ammount = FastMath.TWO_PI / PICKUP_COUNT; + for(float angle = 0; angle < FastMath.TWO_PI; angle += ammount) { + Geometry pickUp = new Geometry("pickUp" + (index++), new Box(PICKUP_SIZE,PICKUP_SIZE, PICKUP_SIZE)); + pickUp.setShadowMode(ShadowMode.CastAndReceive); + pickUp.setMaterial(materialYellow); + pickUp.setLocalRotation(rotation.fromAngles( + FastMath.rand.nextFloat() * FastMath.TWO_PI, + FastMath.rand.nextFloat() * FastMath.TWO_PI, + FastMath.rand.nextFloat() * FastMath.TWO_PI)); + + rotation.fromAngles(0.0f, angle, 0.0f); + rotation.mult(translation, pickUp.getLocalTranslation()); + pickUps.attachChild(pickUp); + + pickUp.addControl(new GhostControl(new SphereCollisionShape(PICKUP_SIZE))); + + + space.addAll(pickUp); + //space.addCollisionListener(pickUpControl); + } + rootNode.attachChild(pickUps); + + // Create player + // TODO: create your own player mesh + Geometry playerGeometry = new Geometry("player", new Sphere(16, 32, PLAYER_RADIUS)); + playerGeometry.setShadowMode(ShadowMode.CastAndReceive); + playerGeometry.setLocalTranslation(PLAYER_START.clone()); + playerGeometry.setMaterial(logoMaterial); + + // Store control for applying forces + // TODO: create your own player control + player = new RigidBodyControl(new SphereCollisionShape(PLAYER_RADIUS), PLAYER_MASS); + player.setRestitution(PLAYER_REST); + + playerGeometry.addControl(player); + + rootNode.attachChild(playerGeometry); + space.addAll(playerGeometry); + + inputManager.addMapping(INPUT_MAPPING_FORWARD, new KeyTrigger(KeyInput.KEY_UP) + , new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping(INPUT_MAPPING_BACKWARD, new KeyTrigger(KeyInput.KEY_DOWN) + , new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping(INPUT_MAPPING_LEFT, new KeyTrigger(KeyInput.KEY_LEFT) + , new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping(INPUT_MAPPING_RIGHT, new KeyTrigger(KeyInput.KEY_RIGHT) + , new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping(INPUT_MAPPING_RESET, new KeyTrigger(KeyInput.KEY_R)); + inputManager.addListener(this, INPUT_MAPPING_FORWARD, INPUT_MAPPING_BACKWARD + , INPUT_MAPPING_LEFT, INPUT_MAPPING_RIGHT, INPUT_MAPPING_RESET); + + // init UI + infoText = new BitmapText(guiFont, false); + infoText.setText(INFO_MESSAGE); + guiNode.attachChild(infoText); + + scoreText = new BitmapText(guiFont, false); + scoreText.setText("Score: 0"); + guiNode.attachChild(scoreText); + + messageText = new BitmapText(guiFont, false); + messageText.setText(MESSAGE); + messageText.setLocalScale(0.0f); + guiNode.attachChild(messageText); + + infoText.setLocalTranslation(0.0f, cam.getHeight(), 0.0f); + scoreText.setLocalTranslation((cam.getWidth() - scoreText.getLineWidth()) / 2.0f, + scoreText.getLineHeight(), 0.0f); + messageText.setLocalTranslation((cam.getWidth() - messageText.getLineWidth()) / 2.0f, + (cam.getHeight() - messageText.getLineHeight()) / 2, 0.0f); + + // init shadows + FilterPostProcessor processor = new FilterPostProcessor(assetManager); + DirectionalLightShadowFilter filter = new DirectionalLightShadowFilter(assetManager, 2048, 1); + filter.setLight(sun); + processor.addFilter(filter); + viewPort.addProcessor(processor); + + } + + @Override + public void simpleUpdate(float tpf) { + // Update and position the score + scoreText.setText("Score: " + score); + scoreText.setLocalTranslation((cam.getWidth() - scoreText.getLineWidth()) / 2.0f, + scoreText.getLineHeight(), 0.0f); + + // Rotate all the pickups + float pickUpSpeed = PICKUP_SPEED * tpf; + for(Spatial pickUp : pickUps.getChildren()) { + pickUp.rotate(pickUpSpeed, pickUpSpeed, pickUpSpeed); + } + + Vector3f centralForce = new Vector3f(); + + if(keyForward) centralForce.addLocal(cam.getDirection()); + if(keyBackward) centralForce.addLocal(cam.getDirection().negate()); + if(keyLeft) centralForce.addLocal(cam.getLeft()); + if(keyRight) centralForce.addLocal(cam.getLeft().negate()); + + if(!Vector3f.ZERO.equals(centralForce)) { + centralForce.setY(0); // stop ball from pusing down or flying up + centralForce.normalizeLocal(); // normalize force + centralForce.multLocal(PLAYER_FORCE); // scale vector to force + + player.applyCentralForce(centralForce); // apply force to player + } + + cam.lookAt(player.getPhysicsLocation(), Vector3f.UNIT_Y); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + switch(name) { + case INPUT_MAPPING_FORWARD: + keyForward = isPressed; + break; + case INPUT_MAPPING_BACKWARD: + keyBackward = isPressed; + break; + case INPUT_MAPPING_LEFT: + keyLeft = isPressed; + break; + case INPUT_MAPPING_RIGHT: + keyRight = isPressed; + break; + case INPUT_MAPPING_RESET: + enqueue(new Callable() { + @Override + public Void call() { + reset(); + return null; + } + }); + break; + } + } + @Override + public void collision(PhysicsCollisionEvent event) { + Spatial nodeA = event.getNodeA(); + Spatial nodeB = event.getNodeB(); + + String nameA = nodeA == null ? "" : nodeA.getName(); + String nameB = nodeB == null ? "" : nodeB.getName(); + + if(nameA.equals("player") && nameB.startsWith("pickUp")) { + GhostControl pickUpControl = nodeB.getControl(GhostControl.class); + if(pickUpControl != null && pickUpControl.isEnabled()) { + pickUpControl.setEnabled(false); + nodeB.removeFromParent(); + nodeB.setLocalScale(0.0f); + score += 1; + if(score >= PICKUP_COUNT) { + messageText.setLocalScale(1.0f); + } + } + } else if(nameA.startsWith("pickUp") && nameB.equals("player")) { + GhostControl pickUpControl = nodeA.getControl(GhostControl.class); + if(pickUpControl != null && pickUpControl.isEnabled()) { + pickUpControl.setEnabled(false); + nodeA.setLocalScale(0.0f); + score += 1; + if(score >= PICKUP_COUNT) { + messageText.setLocalScale(1.0f); + } + } + } + } + + private void reset() { + // Reset the pickups + for(Spatial pickUp : pickUps.getChildren()) { + GhostControl pickUpControl = pickUp.getControl(GhostControl.class); + if(pickUpControl != null) { + pickUpControl.setEnabled(true); + } + pickUp.setLocalScale(1.0f); + } + // Reset the player + player.setPhysicsLocation(PLAYER_START.clone()); + player.setAngularVelocity(Vector3f.ZERO.clone()); + player.setLinearVelocity(Vector3f.ZERO.clone()); + // Reset the score + score = 0; + // Reset the message + messageText.setLocalScale(0.0f); + } + +} diff --git a/JmeTests/src/jme3test/games/WorldOfInception.java b/JmeTests/src/jme3test/games/WorldOfInception.java new file mode 100644 index 0000000..6e15926 --- /dev/null +++ b/JmeTests/src/jme3test/games/WorldOfInception.java @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.games; + +import com.jme3.app.Application; +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.AbstractAppState; +import com.jme3.app.state.AppStateManager; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.MeshCollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.debug.DebugTools; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Ray; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.FogFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * WorldOfInception - Find the galaxy center ;) + * + * @author normenhansen + */ +public class WorldOfInception extends SimpleApplication implements AnalogListener { + + //Assumptions: POI radius in world == 1, only one player, vector3f hash describes enough worlds + private static final Logger logger = Logger.getLogger(WorldOfInception.class.getName()); + private static final Random random = new Random(System.currentTimeMillis()); + private static final float scaleDist = 10; + private static final float poiRadius = 100; + private static final int poiCount = 30; + private static Material poiMaterial; + private static Mesh poiMesh; + private static Material ballMaterial; + private static Mesh ballMesh; + private static CollisionShape poiHorizonCollisionShape; + private static CollisionShape poiCollisionShape; + private static CollisionShape ballCollisionShape; + private InceptionLevel currentLevel; + private final Vector3f walkDirection = new Vector3f(); + private static DebugTools debugTools; + + public WorldOfInception() { + //base level vector position hash == seed + super(new InceptionLevel(null, Vector3f.ZERO)); + currentLevel = super.getStateManager().getState(InceptionLevel.class); + currentLevel.takeOverParent(); + currentLevel.getRootNode().setLocalScale(Vector3f.UNIT_XYZ); + currentLevel.getRootNode().setLocalTranslation(Vector3f.ZERO); + } + + public static void main(String[] args) { + WorldOfInception app = new WorldOfInception(); + app.start(); + } + + @Override + public void simpleInitApp() { + //set far frustum only so we see the outer world longer + cam.setFrustumFar(10000); + cam.setLocation(Vector3f.ZERO); + debugTools = new DebugTools(assetManager); + rootNode.attachChild(debugTools.debugNode); + poiMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + poiMaterial.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + poiMesh = new Sphere(16, 16, 1f); + + ballMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + ballMaterial.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + ballMaterial.setColor("Color", ColorRGBA.Red); + ballMesh = new Sphere(16, 16, 1.0f); + + poiHorizonCollisionShape = new MeshCollisionShape(new Sphere(128, 128, poiRadius)); + poiCollisionShape = new SphereCollisionShape(1f); + ballCollisionShape = new SphereCollisionShape(1f); + setupKeys(); + setupDisplay(); + setupFog(); + } + + private void setupKeys() { + inputManager.addMapping("StrafeLeft", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("StrafeRight", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("StrafeUp", new KeyTrigger(KeyInput.KEY_Q)); + inputManager.addMapping("StrafeDown", new KeyTrigger(KeyInput.KEY_Z), new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("Return", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("Esc", new KeyTrigger(KeyInput.KEY_ESCAPE)); + inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addListener(this, "StrafeLeft", "StrafeRight", "Forward", "Back", "StrafeUp", "StrafeDown", "Space", "Reset", "Esc", "Up", "Down", "Left", "Right"); + } + + private void setupDisplay() { + if (fpsText == null) { + fpsText = new BitmapText(guiFont, false); + } + fpsText.setLocalScale(0.7f, 0.7f, 0.7f); + fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0); + fpsText.setText(""); + fpsText.setCullHint(Spatial.CullHint.Never); + guiNode.attachChild(fpsText); + } + + private void setupFog() { + // use fog to give more sense of depth + FilterPostProcessor fpp; + FogFilter fog; + fpp=new FilterPostProcessor(assetManager); + fog=new FogFilter(); + fog.setFogColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)); + fog.setFogDistance(poiRadius); + fog.setFogDensity(2.0f); + fpp.addFilter(fog); + viewPort.addProcessor(fpp); + } + + public void onAnalog(String name, float value, float tpf) { + Vector3f left = rootNode.getLocalRotation().mult(Vector3f.UNIT_X.negate()); + Vector3f forward = rootNode.getLocalRotation().mult(Vector3f.UNIT_Z.negate()); + Vector3f up = rootNode.getLocalRotation().mult(Vector3f.UNIT_Y); + //TODO: properly scale input based on current scaling level + tpf = tpf * (10 - (9.0f * currentLevel.getCurrentScaleAmount())); + if (name.equals("StrafeLeft") && value > 0) { + walkDirection.addLocal(left.mult(tpf)); + } else if (name.equals("StrafeRight") && value > 0) { + walkDirection.addLocal(left.negate().multLocal(tpf)); + } else if (name.equals("Forward") && value > 0) { + walkDirection.addLocal(forward.mult(tpf)); + } else if (name.equals("Back") && value > 0) { + walkDirection.addLocal(forward.negate().multLocal(tpf)); + } else if (name.equals("StrafeUp") && value > 0) { + walkDirection.addLocal(up.mult(tpf)); + } else if (name.equals("StrafeDown") && value > 0) { + walkDirection.addLocal(up.negate().multLocal(tpf)); + } else if (name.equals("Up") && value > 0) { + //TODO: rotate rootNode, needs to be global + } else if (name.equals("Down") && value > 0) { + } else if (name.equals("Left") && value > 0) { + } else if (name.equals("Right") && value > 0) { + } else if (name.equals("Esc")) { + stop(); + } + } + + @Override + public void simpleUpdate(float tpf) { + currentLevel = currentLevel.getCurrentLevel(); + currentLevel.move(walkDirection); + fpsText.setText("Location: " + currentLevel.getCoordinates()); + walkDirection.set(Vector3f.ZERO); + } + + public static class InceptionLevel extends AbstractAppState { + + private final InceptionLevel parent; + private final Vector3f inParentPosition; + private SimpleApplication application; + private BulletAppState physicsState; + private Node rootNode; + private Vector3f playerPos; + private InceptionLevel currentActiveChild; + private InceptionLevel currentReturnLevel; + private float curScaleAmount = 0; + + public InceptionLevel(InceptionLevel parent, Vector3f inParentPosition) { + this.parent = parent; + this.inParentPosition = inParentPosition; + } + + @Override + public void update(float tpf) { + super.update(tpf); + if (currentReturnLevel != this) { + return; + } + debugTools.setYellowArrow(new Vector3f(0, 0, -2), playerPos.divide(poiRadius)); + float curLocalDist = getPlayerPosition().length(); + // If we are outside the range of one point of interest, move out to + // the next upper level + if (curLocalDist > poiRadius + FastMath.ZERO_TOLERANCE) { //DAFUQ normalize? + if (parent == null) { + //TODO: could add new nodes coming in instead for literally endless space + logger.log(Level.INFO, "Hit event horizon"); + currentReturnLevel = this; + return; + } + //give to parent + logger.log(Level.INFO, "give to parent");; + parent.takeOverChild(inParentPosition.add(playerPos.normalize())); + application.getStateManager().attach(parent); + currentReturnLevel = parent; + return; + } + + AppStateManager stateManager = application.getStateManager(); + // We create child positions based on the parent position hash so we + // should in practice get the same galaxy w/o too many doubles + // with each run with the same root vector. + Vector3f[] vectors = getPositions(poiCount, inParentPosition.hashCode()); + for (int i = 0; i < vectors.length; i++) { + Vector3f vector3f = vectors[i]; + //negative rootNode location is our actual player position + Vector3f distVect = vector3f.subtract(playerPos); + float distance = distVect.length(); + if (distance <= 1) { + checkActiveChild(vector3f); + float percent = 0; + curScaleAmount = 0; + this.scaleAsParent(percent, playerPos, distVect); + currentActiveChild.scaleAsChild(percent, distVect); + logger.log(Level.INFO, "Give over to child {0}", currentActiveChild); + currentActiveChild.takeOverParent(); + stateManager.detach(this); + currentReturnLevel = currentActiveChild; + return; + } else if (distance <= 1 + scaleDist) { + debugTools.setRedArrow(Vector3f.ZERO, distVect); + checkActiveChild(vector3f); + //TODO: scale percent nicer for less of an "explosion" effect + float percent = 1 - mapValue(distance - 1, 0, scaleDist, 0, 1); + curScaleAmount = percent; + rootNode.getChild(i).setCullHint(Spatial.CullHint.Always); + this.scaleAsParent(percent, playerPos, distVect); + currentActiveChild.scaleAsChild(percent, distVect); + currentReturnLevel = this; + return; + } else if (currentActiveChild != null && currentActiveChild.getPositionInParent().equals(vector3f)) { + //TODO: doing this here causes problems when close to multiple pois + rootNode.getChild(i).setCullHint(Spatial.CullHint.Inherit); + } + } + checkActiveChild(null); + curScaleAmount = 0; + rootNode.setLocalScale(1); + rootNode.setLocalTranslation(playerPos.negate()); + debugTools.setRedArrow(Vector3f.ZERO, Vector3f.ZERO); + debugTools.setBlueArrow(Vector3f.ZERO, Vector3f.ZERO); + debugTools.setGreenArrow(Vector3f.ZERO, Vector3f.ZERO); + } + + private void checkActiveChild(Vector3f vector3f) { + AppStateManager stateManager = application.getStateManager(); + if(vector3f == null){ + if(currentActiveChild != null){ + logger.log(Level.INFO, "Detach child {0}", currentActiveChild); + stateManager.detach(currentActiveChild); + currentActiveChild = null; + } + return; + } + if (currentActiveChild == null) { + currentActiveChild = new InceptionLevel(this, vector3f); + stateManager.attach(currentActiveChild); + logger.log(Level.INFO, "Attach child {0}", currentActiveChild); + } else if (!currentActiveChild.getPositionInParent().equals(vector3f)) { + logger.log(Level.INFO, "Switching from child {0}", currentActiveChild); + stateManager.detach(currentActiveChild); + currentActiveChild = new InceptionLevel(this, vector3f); + stateManager.attach(currentActiveChild); + logger.log(Level.INFO, "Attach child {0}", currentActiveChild); + } + } + + private void scaleAsChild(float percent, Vector3f dist) { + float childScale = mapValue(percent, 1.0f / poiRadius, 1); + Vector3f distToHorizon = dist.normalize(); + Vector3f scaledDistToHorizon = distToHorizon.mult(childScale * poiRadius); + Vector3f rootOff = dist.add(scaledDistToHorizon); + debugTools.setBlueArrow(Vector3f.ZERO, rootOff); + getRootNode().setLocalScale(childScale); + getRootNode().setLocalTranslation(rootOff); + //prepare player position already + Vector3f playerPosition = dist.normalize().mult(-poiRadius); + setPlayerPosition(playerPosition); + } + + private void scaleAsParent(float percent, Vector3f playerPos, Vector3f dist) { + float scale = mapValue(percent, 1.0f, poiRadius); + Vector3f distToHorizon = dist.subtract(dist.normalize()); + Vector3f offLocation = playerPos.add(distToHorizon); + Vector3f rootOff = offLocation.mult(scale).negate(); + rootOff.addLocal(dist); + debugTools.setGreenArrow(Vector3f.ZERO, offLocation); + getRootNode().setLocalScale(scale); + getRootNode().setLocalTranslation(rootOff); + } + + public void takeOverParent() { + //got playerPos from scaleAsChild before + getPlayerPosition().normalizeLocal().multLocal(poiRadius); + currentReturnLevel = this; + } + + public void takeOverChild(Vector3f playerPos) { + this.playerPos.set(playerPos); + currentReturnLevel = this; + } + + public InceptionLevel getLastLevel(Ray pickRay) { + // TODO: get a level based on positions getting ever more accurate, + // from any given position + return null; + } + + public InceptionLevel getLevel(Vector3f... location) { + // TODO: get a level based on positions getting ever more accurate, + // from any given position + return null; + } + + private void initData() { + getRootNode(); + physicsState = new BulletAppState(); + physicsState.startPhysics(); + physicsState.getPhysicsSpace().setGravity(Vector3f.ZERO); + //horizon + physicsState.getPhysicsSpace().add(new RigidBodyControl(poiHorizonCollisionShape, 0)); + int hashCode = inParentPosition.hashCode(); + Vector3f[] positions = getPositions(poiCount, hashCode); + for (int i = 0; i < positions.length; i++) { + Vector3f vector3f = positions[i]; + Geometry poiGeom = new Geometry("poi", poiMesh); + poiGeom.setLocalTranslation(vector3f); + poiGeom.setMaterial(poiMaterial); + RigidBodyControl control = new RigidBodyControl(poiCollisionShape, 0); + //!!! Important + control.setApplyPhysicsLocal(true); + poiGeom.addControl(control); + physicsState.getPhysicsSpace().add(poiGeom); + rootNode.attachChild(poiGeom); + + } + //add balls after so first 10 geoms == locations + for (int i = 0; i < positions.length; i++) { + Vector3f vector3f = positions[i]; + Geometry ball = getRandomBall(vector3f); + physicsState.getPhysicsSpace().add(ball); + rootNode.attachChild(ball); + } + + } + + private Geometry getRandomBall(Vector3f location) { + Vector3f localLocation = new Vector3f(); + localLocation.set(location); + localLocation.addLocal(new Vector3f(random.nextFloat() - 0.5f, random.nextFloat() - 0.5f, random.nextFloat() - 0.5f).normalize().mult(3)); + Geometry poiGeom = new Geometry("ball", ballMesh); + poiGeom.setLocalTranslation(localLocation); + poiGeom.setMaterial(ballMaterial); + RigidBodyControl control = new RigidBodyControl(ballCollisionShape, 1); + //!!! Important + control.setApplyPhysicsLocal(true); + poiGeom.addControl(control); + float x = (random.nextFloat() - 0.5f) * 100; + float y = (random.nextFloat() - 0.5f) * 100; + float z = (random.nextFloat() - 0.5f) * 100; + control.setLinearVelocity(new Vector3f(x, y, z)); + return poiGeom; + } + + private void cleanupData() { + physicsState.stopPhysics(); + //TODO: remove all objects? + physicsState = null; + rootNode = null; + } + + @Override + public void initialize(AppStateManager stateManager, Application app) { + super.initialize(stateManager, app); + //only generate data and attach node when we are actually attached (or picking) + initData(); + application = (SimpleApplication) app; + application.getRootNode().attachChild(getRootNode()); + application.getStateManager().attach(physicsState); + } + + @Override + public void cleanup() { + super.cleanup(); + //detach everything when we are detached + application.getRootNode().detachChild(rootNode); + application.getStateManager().detach(physicsState); + cleanupData(); + } + + public Node getRootNode() { + if (rootNode == null) { + rootNode = new Node("ZoomLevel"); + if (parent != null) { + rootNode.setLocalScale(1.0f / poiRadius); + } + } + return rootNode; + } + + public Vector3f getPositionInParent() { + return inParentPosition; + } + + public Vector3f getPlayerPosition() { + if (playerPos == null) { + playerPos = new Vector3f(); + } + return playerPos; + } + + public void setPlayerPosition(Vector3f vec) { + if (playerPos == null) { + playerPos = new Vector3f(); + } + playerPos.set(vec); + } + + public void move(Vector3f dir) { + if (playerPos == null) { + playerPos = new Vector3f(); + } + playerPos.addLocal(dir); + } + + public float getCurrentScaleAmount() { + return curScaleAmount; + } + + public InceptionLevel getParent() { + return parent; + } + + public InceptionLevel getCurrentLevel() { + return currentReturnLevel; + } + + public String getCoordinates() { + InceptionLevel cur = this; + StringBuilder strb = new StringBuilder(); + strb.insert(0, this.getPlayerPosition()); + strb.insert(0, this.getPositionInParent() + " / "); + cur = cur.getParent(); + while (cur != null) { + strb.insert(0, cur.getPositionInParent() + " / "); + cur = cur.getParent(); + } + return strb.toString(); + } + } + + public static Vector3f[] getPositions(int count, long seed) { + Random rnd = new Random(seed); + Vector3f[] vectors = new Vector3f[count]; + for (int i = 0; i < count; i++) { + vectors[i] = new Vector3f((rnd.nextFloat() - 0.5f) * poiRadius, + (rnd.nextFloat() - 0.5f) * poiRadius, + (rnd.nextFloat() - 0.5f) * poiRadius); + } + return vectors; + } + + /** + * Maps a value from 0-1 to a range from min to max. + * + * @param x + * @param min + * @param max + * @return + */ + public static float mapValue(float x, float min, float max) { + return mapValue(x, 0, 1, min, max); + } + + /** + * Maps a value from inputMin to inputMax to a range from min to max. + * + * @param x + * @param inputMin + * @param inputMax + * @param min + * @param max + * @return + */ + public static float mapValue(float x, float inputMin, float inputMax, float min, float max) { + return (x - inputMin) * (max - min) / (inputMax - inputMin) + min; + } +} diff --git a/JmeTests/src/jme3test/gui/TestBitmapFont.java b/JmeTests/src/jme3test/gui/TestBitmapFont.java new file mode 100644 index 0000000..11fc69a --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestBitmapFont.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.font.LineWrapMode; +import com.jme3.font.Rectangle; +import com.jme3.input.KeyInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.event.*; + +public class TestBitmapFont extends SimpleApplication { + + private String txtB = + "ABCDEFGHIKLMNOPQRSTUVWXYZ1234567 890`~!@#$%^&*()-=_+[]\\;',./{}|:<>?"; + + private BitmapText txt; + private BitmapText txt2; + private BitmapText txt3; + + public static void main(String[] args){ + TestBitmapFont app = new TestBitmapFont(); + app.start(); + } + + @Override + public void simpleInitApp() { + inputManager.addMapping("WordWrap", new KeyTrigger(KeyInput.KEY_TAB)); + inputManager.addListener(keyListener, "WordWrap"); + inputManager.addRawInputListener(textListener); + + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + txt = new BitmapText(fnt, false); + txt.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight())); + txt.setSize(fnt.getPreferredSize() * 2f); + txt.setText(txtB); + txt.setLocalTranslation(0, txt.getHeight(), 0); + guiNode.attachChild(txt); + + txt2 = new BitmapText(fnt, false); + txt2.setSize(fnt.getPreferredSize() * 1.2f); + txt2.setText("Text without restriction. \nText without restriction. Text without restriction. Text without restriction"); + txt2.setLocalTranslation(0, txt2.getHeight(), 0); + guiNode.attachChild(txt2); + + txt3 = new BitmapText(fnt, false); + txt3.setBox(new Rectangle(0, 0, settings.getWidth(), 0)); + txt3.setText("Press Tab to toggle word-wrap. type text and enter to input text"); + txt3.setLocalTranslation(0, settings.getHeight()/2, 0); + guiNode.attachChild(txt3); + } + + private ActionListener keyListener = new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("WordWrap") && !isPressed) { + txt.setLineWrapMode( txt.getLineWrapMode() == LineWrapMode.Word ? + LineWrapMode.NoWrap : LineWrapMode.Word ); + } + } + }; + + private RawInputListener textListener = new RawInputListener() { + private StringBuilder str = new StringBuilder(); + + @Override + public void onMouseMotionEvent(MouseMotionEvent evt) { } + + @Override + public void onMouseButtonEvent(MouseButtonEvent evt) { } + + @Override + public void onKeyEvent(KeyInputEvent evt) { + if (evt.isReleased()) + return; + if (evt.getKeyChar() == '\n' || evt.getKeyChar() == '\r') { + txt3.setText(str.toString()); + str.setLength(0); + } else { + str.append(evt.getKeyChar()); + } + } + + @Override + public void onJoyButtonEvent(JoyButtonEvent evt) { } + + @Override + public void onJoyAxisEvent(JoyAxisEvent evt) { } + + @Override + public void endInput() { } + + @Override + public void beginInput() { } + + @Override + public void onTouchEvent(TouchEvent evt) { } + + }; + +} diff --git a/JmeTests/src/jme3test/gui/TestBitmapText3D.java b/JmeTests/src/jme3test/gui/TestBitmapText3D.java new file mode 100644 index 0000000..ce32e7a --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestBitmapText3D.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.font.Rectangle; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +public class TestBitmapText3D extends SimpleApplication { + + private String txtB = + "ABCDEFGHIKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()-=_+[]\\;',./{}|:<>?"; + + public static void main(String[] args){ + TestBitmapText3D app = new TestBitmapText3D(); + app.start(); + } + + @Override + public void simpleInitApp() { + Quad q = new Quad(6, 3); + Geometry g = new Geometry("quad", q); + g.setLocalTranslation(0, -3, -0.0001f); + g.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(g); + + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText txt = new BitmapText(fnt, false); + txt.setBox(new Rectangle(0, 0, 6, 3)); + txt.setQueueBucket(Bucket.Transparent); + txt.setSize( 0.5f ); + txt.setText(txtB); + rootNode.attachChild(txt); + } + +} diff --git a/JmeTests/src/jme3test/gui/TestCursor.java b/JmeTests/src/jme3test/gui/TestCursor.java new file mode 100644 index 0000000..d2b10fc --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestCursor.java @@ -0,0 +1,77 @@ +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.cursors.plugins.JmeCursor; +import java.util.ArrayList; + +/** + * This test class demonstrate how to change cursor in jME3. + * + * NOTE: This will not work on Android as it does not support cursors. + * + * Cursor test + * @author MadJack + */ +public class TestCursor extends SimpleApplication { + + private ArrayList cursors = new ArrayList(); + private long sysTime; + private int count = 0; + + public static void main(String[] args){ + TestCursor app = new TestCursor(); + + app.setShowSettings(false); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + // We need the cursor to be visible. If it is not visible the cursor + // will still be "used" and loaded, you just won't see it on the screen. + inputManager.setCursorVisible(true); + + /* + * To make jME3 use a custom cursor it is as simple as putting the + * .cur/.ico/.ani file in an asset directory. Here we use + * "Textures/GUI/Cursors". + * + * For the purpose of this demonstration we load 3 different cursors and add them + * into an array list and switch cursor every 8 seconds. + * + * The first ico has been made by Sirea and the set can be found here: + * http://www.rw-designer.com/icon-set/nyan-cat + * + * The second cursor has been made by Virum64 and is Public Domain. + * http://www.rw-designer.com/cursor-set/memes-faces-v64 + * + * The animated cursor has been made by Pointer Adic and can be found here: + * http://www.rw-designer.com/cursor-set/monkey + */ + cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/meme.cur")); + cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/nyancat.ico")); + cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/monkey.ani")); + + sysTime = System.currentTimeMillis(); + inputManager.setMouseCursor(cursors.get(count)); + } + + @Override + public void simpleUpdate(float tpf) { + long currentTime = System.currentTimeMillis(); + + if (currentTime - sysTime > 8000) { + count++; + if (count >= cursors.size()) { + count = 0; + } + sysTime = currentTime; + // 8 seconds have passed, + // tell jME3 to swith to a different cursor. + inputManager.setMouseCursor(cursors.get(count)); + } + + } +} + diff --git a/JmeTests/src/jme3test/gui/TestOrtho.java b/JmeTests/src/jme3test/gui/TestOrtho.java new file mode 100644 index 0000000..2e252aa --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestOrtho.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.ui.Picture; + +public class TestOrtho extends SimpleApplication { + + public static void main(String[] args){ + TestOrtho app = new TestOrtho(); + app.start(); + } + + public void simpleInitApp() { + Picture p = new Picture("Picture"); + p.move(0, 0, -1); // make it appear behind stats view + p.setPosition(0, 0); + p.setWidth(settings.getWidth()); + p.setHeight(settings.getHeight()); + p.setImage(assetManager, "Interface/Logo/Monkey.png", false); + + // attach geometry to orthoNode + guiNode.attachChild(p); + } + +} diff --git a/JmeTests/src/jme3test/gui/TestSoftwareMouse.java b/JmeTests/src/jme3test/gui/TestSoftwareMouse.java new file mode 100644 index 0000000..44bee28 --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestSoftwareMouse.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.*; +import com.jme3.math.FastMath; +import com.jme3.system.AppSettings; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.ui.Picture; + +public class TestSoftwareMouse extends SimpleApplication { + + private Picture cursor; + + private RawInputListener inputListener = new RawInputListener() { + + private float x = 0, y = 0; + + public void beginInput() { + } + public void endInput() { + } + public void onJoyAxisEvent(JoyAxisEvent evt) { + } + public void onJoyButtonEvent(JoyButtonEvent evt) { + } + public void onMouseMotionEvent(MouseMotionEvent evt) { + x += evt.getDX(); + y += evt.getDY(); + + // Prevent mouse from leaving screen + AppSettings settings = TestSoftwareMouse.this.settings; + x = FastMath.clamp(x, 0, settings.getWidth()); + y = FastMath.clamp(y, 0, settings.getHeight()); + + // adjust for hotspot + cursor.setPosition(x, y - 64); + } + public void onMouseButtonEvent(MouseButtonEvent evt) { + } + public void onKeyEvent(KeyInputEvent evt) { + } + public void onTouchEvent(TouchEvent evt) { + } + }; + + public static void main(String[] args){ + TestSoftwareMouse app = new TestSoftwareMouse(); + +// AppSettings settings = new AppSettings(true); +// settings.setFrameRate(60); +// app.setSettings(settings); + + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); +// inputManager.setCursorVisible(false); + + Texture tex = assetManager.loadTexture("Interface/Logo/Cursor.png"); + + cursor = new Picture("cursor"); + cursor.setTexture(assetManager, (Texture2D) tex, true); + cursor.setWidth(64); + cursor.setHeight(64); + guiNode.attachChild(cursor); + + inputManager.addRawInputListener(inputListener); + +// Image img = tex.getImage(); +// ByteBuffer data = img.getData(0); +// IntBuffer image = BufferUtils.createIntBuffer(64 * 64); +// for (int y = 0; y < 64; y++){ +// for (int x = 0; x < 64; x++){ +// int rgba = data.getInt(); +// image.put(rgba); +// } +// } +// image.clear(); +// +// try { +// Cursor cur = new Cursor(64, 64, 2, 62, 1, image, null); +// Mouse.setNativeCursor(cur); +// } catch (LWJGLException ex) { +// Logger.getLogger(TestSoftwareMouse.class.getName()).log(Level.SEVERE, null, ex); +// } + } +} diff --git a/JmeTests/src/jme3test/gui/TestZOrder.java b/JmeTests/src/jme3test/gui/TestZOrder.java new file mode 100644 index 0000000..5a5683f --- /dev/null +++ b/JmeTests/src/jme3test/gui/TestZOrder.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.gui; + +import com.jme3.app.SimpleApplication; +import com.jme3.ui.Picture; + +public class TestZOrder extends SimpleApplication { + + public static void main(String[] args){ + TestZOrder app = new TestZOrder(); + app.start(); + } + + public void simpleInitApp() { + Picture p = new Picture("Picture1"); + p.move(0,0,-1); + p.setPosition(100, 100); + p.setWidth(100); + p.setHeight(100); + p.setImage(assetManager, "Interface/Logo/Monkey.png", false); + guiNode.attachChild(p); + + Picture p2 = new Picture("Picture2"); + p2.move(0,0,1.001f); + p2.setPosition(150, 150); + p2.setWidth(100); + p2.setHeight(100); + p2.setImage(assetManager, "Interface/Logo/Monkey.png", false); + guiNode.attachChild(p2); + } + +} diff --git a/JmeTests/src/jme3test/helloworld/HelloAnimation.java b/JmeTests/src/jme3test/helloworld/HelloAnimation.java new file mode 100644 index 0000000..bb1587b --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloAnimation.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; + +/** Sample 7 - how to load an OgreXML model and play an animation, + * using channels, a controller, and an AnimEventListener. */ +public class HelloAnimation extends SimpleApplication + implements AnimEventListener { + + Node player; + private AnimChannel channel; + private AnimControl control; + + public static void main(String[] args) { + HelloAnimation app = new HelloAnimation(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.LightGray); + initKeys(); + + /** Add a light source so we can see the model */ + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal()); + rootNode.addLight(dl); + + /** Load a model that contains animation */ + player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + player.setLocalScale(0.5f); + rootNode.attachChild(player); + + /** Create a controller and channels. */ + control = player.getControl(AnimControl.class); + control.addListener(this); + channel = control.createChannel(); + channel.setAnim("stand"); + } + + /** Use this listener to trigger something after an animation is done. */ + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + if (animName.equals("Walk")) { + /** After "walk", reset to "stand". */ + channel.setAnim("stand", 0.50f); + channel.setLoopMode(LoopMode.DontLoop); + channel.setSpeed(1f); + } + } + + /** Use this listener to trigger something between two animations. */ + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + // unused + } + + /** Custom Keybindings: Mapping a named action to a key input. */ + private void initKeys() { + inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(actionListener, "Walk"); + } + + /** Definining the named action that can be triggered by key inputs. */ + private ActionListener actionListener = new ActionListener() { + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("Walk") && !keyPressed) { + if (!channel.getAnimationName().equals("Walk")) { + /** Play the "walk" animation! */ + channel.setAnim("Walk", 0.50f); + channel.setLoopMode(LoopMode.Loop); + } + } + } + }; + +} diff --git a/JmeTests/src/jme3test/helloworld/HelloAssets.java b/JmeTests/src/jme3test/helloworld/HelloAssets.java new file mode 100644 index 0000000..4fb4738 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloAssets.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; + +/** Sample 3 - how to load an OBJ model, and OgreXML model, + * a material/texture, or text. */ +public class HelloAssets extends SimpleApplication { + + public static void main(String[] args) { + HelloAssets app = new HelloAssets(); + app.start(); + } + + @Override + public void simpleInitApp() { + + /** Load a teapot model (OBJ file from test-data) */ + Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + Material mat_default = new Material( assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + teapot.setMaterial(mat_default); + rootNode.attachChild(teapot); + + /** Create a wall (Box with material and texture from test-data) */ + Box box = new Box(2.5f, 2.5f, 1.0f); + Spatial wall = new Geometry("Box", box ); + Material mat_brick = new Material( assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat_brick.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); + wall.setMaterial(mat_brick); + wall.setLocalTranslation(2.0f,-2.5f,0.0f); + rootNode.attachChild(wall); + + /** Display a line of text (default font from test-data) */ + setDisplayStatView(false); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText helloText = new BitmapText(guiFont, false); + helloText.setSize(guiFont.getCharSet().getRenderedSize()); + helloText.setText("Hello World"); + helloText.setLocalTranslation(300, helloText.getLineHeight(), 0); + guiNode.attachChild(helloText); + + /** Load a Ninja model (OgreXML + material + texture from test_data) */ + Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml"); + ninja.scale(0.05f, 0.05f, 0.05f); + ninja.rotate(0.0f, -3.0f, 0.0f); + ninja.setLocalTranslation(0.0f, -5.0f, -2.0f); + rootNode.attachChild(ninja); + /** You must add a light to make the model visible */ + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal()); + rootNode.addLight(sun); + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloAudio.java b/JmeTests/src/jme3test/helloworld/HelloAudio.java new file mode 100644 index 0000000..bc13e01 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloAudio.java @@ -0,0 +1,86 @@ +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData.DataType; +import com.jme3.audio.AudioNode; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** Sample 11 - playing 3D audio. */ +public class HelloAudio extends SimpleApplication { + + private AudioNode audio_gun; + private AudioNode audio_nature; + private Geometry player; + + public static void main(String[] args) { + HelloAudio app = new HelloAudio(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(40); + + /** just a blue box floating in space */ + Box box1 = new Box(1, 1, 1); + player = new Geometry("Player", box1); + Material mat1 = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Blue); + player.setMaterial(mat1); + rootNode.attachChild(player); + + /** custom init methods, see below */ + initKeys(); + initAudio(); + } + + /** We create two audio nodes. */ + private void initAudio() { + /* gun shot sound is to be triggered by a mouse click. */ + audio_gun = new AudioNode(assetManager, + "Sound/Effects/Gun.wav", DataType.Buffer); + audio_gun.setPositional(false); + audio_gun.setLooping(false); + audio_gun.setVolume(2); + rootNode.attachChild(audio_gun); + + /* nature sound - keeps playing in a loop. */ + audio_nature = new AudioNode(assetManager, + "Sound/Environment/Ocean Waves.ogg", DataType.Stream); + audio_nature.setLooping(true); // activate continuous playing + audio_nature.setPositional(true); + audio_nature.setVolume(3); + rootNode.attachChild(audio_nature); + audio_nature.play(); // play continuously! + } + + /** Declaring "Shoot" action, mapping it to a trigger (mouse left click). */ + private void initKeys() { + inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "Shoot"); + } + + /** Defining the "Shoot" action: Play a gun sound. */ + private ActionListener actionListener = new ActionListener() { + @Override + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("Shoot") && !keyPressed) { + audio_gun.playInstance(); // play each instance once! + } + } + }; + + /** Move the listener with the a camera - for 3D audio. */ + @Override + public void simpleUpdate(float tpf) { + listener.setLocation(cam.getLocation()); + listener.setRotation(cam.getRotation()); + } + +} diff --git a/JmeTests/src/jme3test/helloworld/HelloCollision.java b/JmeTests/src/jme3test/helloworld/HelloCollision.java new file mode 100644 index 0000000..60db3b0 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloCollision.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.util.CollisionShapeFactory; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +/** + * Example 9 - How to make walls and floors solid. + * This collision code uses Physics and a custom Action Listener. + * @author normen, with edits by Zathras + */ +public class HelloCollision extends SimpleApplication + implements ActionListener { + + private Spatial sceneModel; + private BulletAppState bulletAppState; + private RigidBodyControl landscape; + private CharacterControl player; + private Vector3f walkDirection = new Vector3f(); + private boolean left = false, right = false, up = false, down = false; + + //Temporary vectors used on each frame. + //They here to avoid instanciating new vectors on each frame + private Vector3f camDir = new Vector3f(); + private Vector3f camLeft = new Vector3f(); + + public static void main(String[] args) { + HelloCollision app = new HelloCollision(); + app.start(); + } + + public void simpleInitApp() { + /** Set up Physics */ + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); + + // We re-use the flyby camera for rotation, while positioning is handled by physics + viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); + flyCam.setMoveSpeed(100); + setUpKeys(); + setUpLight(); + + // We load the scene from the zip file and adjust its size. + assetManager.registerLocator("town.zip", ZipLocator.class); + sceneModel = assetManager.loadModel("main.scene"); + sceneModel.setLocalScale(2f); + + // We set up collision detection for the scene by creating a + // compound collision shape and a static RigidBodyControl with mass zero. + CollisionShape sceneShape = + CollisionShapeFactory.createMeshShape((Node) sceneModel); + landscape = new RigidBodyControl(sceneShape, 0); + sceneModel.addControl(landscape); + + // We set up collision detection for the player by creating + // a capsule collision shape and a CharacterControl. + // The CharacterControl offers extra settings for + // size, stepheight, jumping, falling, and gravity. + // We also put the player in its starting position. + CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1); + player = new CharacterControl(capsuleShape, 0.05f); + player.setJumpSpeed(20); + player.setFallSpeed(30); + player.setGravity(30); + player.setPhysicsLocation(new Vector3f(0, 10, 0)); + + // We attach the scene and the player to the rootnode and the physics space, + // to make them appear in the game world. + rootNode.attachChild(sceneModel); + bulletAppState.getPhysicsSpace().add(landscape); + bulletAppState.getPhysicsSpace().add(player); + } + + private void setUpLight() { + // We add light so we see the scene + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(1.3f)); + rootNode.addLight(al); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White); + dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal()); + rootNode.addLight(dl); + } + + /** We over-write some navigational key mappings here, so we can + * add physics-controlled walking and jumping: */ + private void setUpKeys() { + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, "Left"); + inputManager.addListener(this, "Right"); + inputManager.addListener(this, "Up"); + inputManager.addListener(this, "Down"); + inputManager.addListener(this, "Jump"); + } + + /** These are our custom actions triggered by key presses. + * We do not walk yet, we just keep track of the direction the user pressed. */ + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Left")) { + if (value) { left = true; } else { left = false; } + } else if (binding.equals("Right")) { + if (value) { right = true; } else { right = false; } + } else if (binding.equals("Up")) { + if (value) { up = true; } else { up = false; } + } else if (binding.equals("Down")) { + if (value) { down = true; } else { down = false; } + } else if (binding.equals("Jump")) { + player.jump(); + } + } + + /** + * This is the main event loop--walking happens here. + * We check in which direction the player is walking by interpreting + * the camera direction forward (camDir) and to the side (camLeft). + * The setWalkDirection() command is what lets a physics-controlled player walk. + * We also make sure here that the camera moves with player. + */ + @Override + public void simpleUpdate(float tpf) { + camDir.set(cam.getDirection()).multLocal(0.6f); + camLeft.set(cam.getLeft()).multLocal(0.4f); + walkDirection.set(0, 0, 0); + if (left) { + walkDirection.addLocal(camLeft); + } + if (right) { + walkDirection.addLocal(camLeft.negate()); + } + if (up) { + walkDirection.addLocal(camDir); + } + if (down) { + walkDirection.addLocal(camDir.negate()); + } + player.setWalkDirection(walkDirection); + cam.setLocation(player.getPhysicsLocation()); + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloEffects.java b/JmeTests/src/jme3test/helloworld/HelloEffects.java new file mode 100644 index 0000000..1210c70 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloEffects.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; + +/** Sample 11 - how to create fire, water, and explosion effects. */ +public class HelloEffects extends SimpleApplication { + + public static void main(String[] args) { + HelloEffects app = new HelloEffects(); + app.start(); + } + + @Override + public void simpleInitApp() { + ParticleEmitter fire = + new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30); + Material mat_red = new Material(assetManager, + "Common/MatDefs/Misc/Particle.j3md"); + mat_red.setTexture("Texture", assetManager.loadTexture( + "Effects/Explosion/flame.png")); + fire.setMaterial(mat_red); + fire.setImagesX(2); + fire.setImagesY(2); // 2x2 texture animation + fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red + fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow + fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0)); + fire.setStartSize(1.5f); + fire.setEndSize(0.1f); + fire.setGravity(0, 0, 0); + fire.setLowLife(1f); + fire.setHighLife(3f); + fire.getParticleInfluencer().setVelocityVariation(0.3f); + rootNode.attachChild(fire); + + ParticleEmitter debris = + new ParticleEmitter("Debris", ParticleMesh.Type.Triangle, 10); + Material debris_mat = new Material(assetManager, + "Common/MatDefs/Misc/Particle.j3md"); + debris_mat.setTexture("Texture", assetManager.loadTexture( + "Effects/Explosion/Debris.png")); + debris.setMaterial(debris_mat); + debris.setImagesX(3); + debris.setImagesY(3); // 3x3 texture animation + debris.setSelectRandomImage(true); + debris.setRotateSpeed(4); + debris.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 4, 0)); + debris.setStartColor(ColorRGBA.White); + debris.setGravity(0, 6, 0); + debris.getParticleInfluencer().setVelocityVariation(.60f); + rootNode.attachChild(debris); + debris.emitAllParticles(); + +// ParticleEmitter water = +// new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 20); +// Material mat_blue = new Material(assetManager, +// "Common/MatDefs/Misc/Particle.j3md"); +// mat_blue.setTexture("Texture", assetManager.loadTexture( +// "Effects/Explosion/flame.png")); +// water.setMaterial(mat_blue); +// water.setImagesX(2); +// water.setImagesY(2); // 2x2 texture animation +// water.setStartColor( ColorRGBA.Blue); +// water.setEndColor( ColorRGBA.Cyan); +// water.getParticleInfluencer().setInitialVelocity(new Vector3f(0, -4, 0)); +// water.setStartSize(1f); +// water.setEndSize(1.5f); +// water.setGravity(0,1,0); +// water.setLowLife(1f); +// water.setHighLife(1f); +// water.getParticleInfluencer().setVelocityVariation(0.1f); +// water.setLocalTranslation(0, 6, 0); +// rootNode.attachChild(water); + + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloInput.java b/JmeTests/src/jme3test/helloworld/HelloInput.java new file mode 100644 index 0000000..8bfebc4 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloInput.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** Sample 5 - how to map keys and mousebuttons to actions */ +public class HelloInput extends SimpleApplication { + + public static void main(String[] args) { + HelloInput app = new HelloInput(); + app.start(); + } + protected Geometry player; + Boolean isRunning=true; + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); + player = new Geometry("Player", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + player.setMaterial(mat); + rootNode.attachChild(player); + initKeys(); // load my custom keybinding + } + + /** Custom Keybinding: Map named actions to inputs. */ + private void initKeys() { + /** You can map one or several inputs to one named mapping. */ + inputManager.addMapping("Pause", new KeyTrigger(keyInput.KEY_P)); + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE), // spacebar! + new MouseButtonTrigger(MouseInput.BUTTON_LEFT) ); // left click! + /** Add the named mappings to the action listeners. */ + inputManager.addListener(actionListener,"Pause"); + inputManager.addListener(analogListener,"Left", "Right", "Rotate"); + } + + /** Use this listener for KeyDown/KeyUp events */ + private ActionListener actionListener = new ActionListener() { + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("Pause") && !keyPressed) { + isRunning = !isRunning; + } + } + }; + + /** Use this listener for continuous events */ + private AnalogListener analogListener = new AnalogListener() { + public void onAnalog(String name, float value, float tpf) { + if (isRunning) { + if (name.equals("Rotate")) { + player.rotate(0, value, 0); + } + if (name.equals("Right")) { + player.move((new Vector3f(value, 0,0)) ); + } + if (name.equals("Left")) { + player.move(new Vector3f(-value, 0,0)); + } + } else { + System.out.println("Press P to unpause."); + } + } + }; + +} diff --git a/JmeTests/src/jme3test/helloworld/HelloJME3.java b/JmeTests/src/jme3test/helloworld/HelloJME3.java new file mode 100644 index 0000000..9ffc193 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloJME3.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** Sample 1 - how to get started with the most simple JME 3 application. + * Display a blue 3D cube and view from all sides by + * moving the mouse and pressing the WASD keys. */ +public class HelloJME3 extends SimpleApplication { + + public static void main(String[] args){ + HelloJME3 app = new HelloJME3(); + app.start(); // start the game + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); // create cube shape + Geometry geom = new Geometry("Box", b); // create cube geometry from the shape + Material mat = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material + mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue + geom.setMaterial(mat); // set the cube's material + rootNode.attachChild(geom); // make the cube appear in the scene + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/helloworld/HelloLoop.java b/JmeTests/src/jme3test/helloworld/HelloLoop.java new file mode 100644 index 0000000..f154a05 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloLoop.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** Sample 4 - how to trigger repeating actions from the main event loop. + * In this example, you use the loop to make the player character + * rotate continuously. */ +public class HelloLoop extends SimpleApplication { + + public static void main(String[] args){ + HelloLoop app = new HelloLoop(); + app.start(); + } + + protected Geometry player; + + @Override + public void simpleInitApp() { + /** this blue box is our player character */ + Box b = new Box(1, 1, 1); + player = new Geometry("blue cube", b); + Material mat = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + player.setMaterial(mat); + rootNode.attachChild(player); + } + + /* Use the main event loop to trigger repeating actions. */ + @Override + public void simpleUpdate(float tpf) { + // make the player rotate: + player.rotate(0, 2*tpf, 0); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/helloworld/HelloMaterial.java b/JmeTests/src/jme3test/helloworld/HelloMaterial.java new file mode 100644 index 0000000..9d93492 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloMaterial.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.Texture; +import com.jme3.util.TangentBinormalGenerator; + +/** Sample 6 - how to give an object's surface a material and texture. + * How to make objects transparent. How to make bumpy and shiny surfaces. */ +public class HelloMaterial extends SimpleApplication { + + public static void main(String[] args) { + HelloMaterial app = new HelloMaterial(); + app.start(); + } + + @Override + public void simpleInitApp() { + + /** A simple textured cube -- in good MIP map quality. */ + Box cube1Mesh = new Box( 1f,1f,1f); + Geometry cube1Geo = new Geometry("My Textured Box", cube1Mesh); + cube1Geo.setLocalTranslation(new Vector3f(-3f,1.1f,0f)); + Material cube1Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Texture cube1Tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + cube1Mat.setTexture("ColorMap", cube1Tex); + cube1Geo.setMaterial(cube1Mat); + rootNode.attachChild(cube1Geo); + + /** A translucent/transparent texture, similar to a window frame. */ + Box cube2Mesh = new Box( 1f,1f,0.01f); + Geometry cube2Geo = new Geometry("window frame", cube2Mesh); + Material cube2Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + cube2Mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png")); + cube2Mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); // activate transparency + cube2Geo.setQueueBucket(Bucket.Transparent); + cube2Geo.setMaterial(cube2Mat); + rootNode.attachChild(cube2Geo); + + /** A bumpy rock with a shiny light effect. To make bumpy objects you must create a NormalMap. */ + Sphere sphereMesh = new Sphere(32,32, 2f); + Geometry sphereGeo = new Geometry("Shiny rock", sphereMesh); + sphereMesh.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres + TangentBinormalGenerator.generate(sphereMesh); // for lighting effect + Material sphereMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + sphereMat.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg")); + sphereMat.setTexture("NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png")); + sphereMat.setBoolean("UseMaterialColors",true); + sphereMat.setColor("Diffuse",ColorRGBA.White); + sphereMat.setColor("Specular",ColorRGBA.White); + sphereMat.setFloat("Shininess", 64f); // [0,128] + sphereGeo.setMaterial(sphereMat); + //sphereGeo.setMaterial((Material) assetManager.loadMaterial("Materials/MyCustomMaterial.j3m")); + sphereGeo.setLocalTranslation(0,2,-2); // Move it a bit + sphereGeo.rotate(1.6f, 0, 0); // Rotate it a bit + rootNode.attachChild(sphereGeo); + + /** Must add a light to make the lit object visible! */ + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(1,0,-2).normalizeLocal()); + sun.setColor(ColorRGBA.White); + rootNode.addLight(sun); + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloNode.java b/JmeTests/src/jme3test/helloworld/HelloNode.java new file mode 100644 index 0000000..d70632f --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloNode.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; + +/** Sample 2 - How to use nodes as handles to manipulate objects in the scene. + * You can rotate, translate, and scale objects by manipulating their parent nodes. + * The Root Node is special: Only what is attached to the Root Node appears in the scene. */ +public class HelloNode extends SimpleApplication { + + public static void main(String[] args){ + HelloNode app = new HelloNode(); + app.start(); + } + + @Override + public void simpleInitApp() { + + /** create a blue box at coordinates (1,-1,1) */ + Box box1 = new Box(1,1,1); + Geometry blue = new Geometry("Box", box1); + blue.setLocalTranslation(new Vector3f(1,-1,1)); + Material mat1 = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Blue); + blue.setMaterial(mat1); + + /** create a red box straight above the blue one at (1,3,1) */ + Box box2 = new Box(1,1,1); + Geometry red = new Geometry("Box", box2); + red.setLocalTranslation(new Vector3f(1,3,1)); + Material mat2 = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setColor("Color", ColorRGBA.Red); + red.setMaterial(mat2); + + /** Create a pivot node at (0,0,0) and attach it to the root node */ + Node pivot = new Node("pivot"); + rootNode.attachChild(pivot); // put this node in the scene + + /** Attach the two boxes to the *pivot* node. (And transitively to the root node.) */ + pivot.attachChild(blue); + pivot.attachChild(red); + /** Rotate the pivot node: Note that both boxes have rotated! */ + pivot.rotate(.4f,.4f,0f); + } +} + diff --git a/JmeTests/src/jme3test/helloworld/HelloPhysics.java b/JmeTests/src/jme3test/helloworld/HelloPhysics.java new file mode 100644 index 0000000..75777e5 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloPhysics.java @@ -0,0 +1,228 @@ +/** + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.font.BitmapText; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Sphere.TextureMode; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + +/** + * Example 12 - how to give objects physical properties so they bounce and fall. + * @author base code by double1984, updated by zathras + */ +public class HelloPhysics extends SimpleApplication { + + public static void main(String args[]) { + HelloPhysics app = new HelloPhysics(); + app.start(); + } + + /** Prepare the Physics Application State (jBullet) */ + private BulletAppState bulletAppState; + + /** Prepare Materials */ + Material wall_mat; + Material stone_mat; + Material floor_mat; + + /** Prepare geometries and physical nodes for bricks and cannon balls. */ + private RigidBodyControl brick_phy; + private static final Box box; + private RigidBodyControl ball_phy; + private static final Sphere sphere; + private RigidBodyControl floor_phy; + private static final Box floor; + + /** dimensions used for bricks and wall */ + private static final float brickLength = 0.48f; + private static final float brickWidth = 0.24f; + private static final float brickHeight = 0.12f; + + static { + /** Initialize the cannon ball geometry */ + sphere = new Sphere(32, 32, 0.4f, true, false); + sphere.setTextureMode(TextureMode.Projected); + /** Initialize the brick geometry */ + box = new Box(brickLength, brickHeight, brickWidth); + box.scaleTextureCoordinates(new Vector2f(1f, .5f)); + /** Initialize the floor geometry */ + floor = new Box(10f, 0.1f, 5f); + floor.scaleTextureCoordinates(new Vector2f(3, 6)); + } + + @Override + public void simpleInitApp() { + /** Set up Physics Game */ + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); + /** Configure cam to look at scene */ + cam.setLocation(new Vector3f(0, 4f, 6f)); + cam.lookAt(new Vector3f(2, 2, 0), Vector3f.UNIT_Y); + /** Initialize the scene, materials, inputs, and physics space */ + initInputs(); + initMaterials(); + initWall(); + initFloor(); + initCrossHairs(); + } + + /** Add InputManager action: Left click triggers shooting. */ + private void initInputs() { + inputManager.addMapping("shoot", + new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "shoot"); + } + + /** + * Every time the shoot action is triggered, a new cannon ball is produced. + * The ball is set up to fly from the camera position in the camera direction. + */ + private ActionListener actionListener = new ActionListener() { + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("shoot") && !keyPressed) { + makeCannonBall(); + } + } + }; + + /** Initialize the materials used in this scene. */ + public void initMaterials() { + wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + wall_mat.setTexture("ColorMap", tex); + + stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); + key2.setGenerateMips(true); + Texture tex2 = assetManager.loadTexture(key2); + stone_mat.setTexture("ColorMap", tex2); + + floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); + key3.setGenerateMips(true); + Texture tex3 = assetManager.loadTexture(key3); + tex3.setWrap(WrapMode.Repeat); + floor_mat.setTexture("ColorMap", tex3); + } + + /** Make a solid floor and add it to the scene. */ + public void initFloor() { + Geometry floor_geo = new Geometry("Floor", floor); + floor_geo.setMaterial(floor_mat); + floor_geo.setLocalTranslation(0, -0.1f, 0); + this.rootNode.attachChild(floor_geo); + /* Make the floor physical with mass 0.0f! */ + floor_phy = new RigidBodyControl(0.0f); + floor_geo.addControl(floor_phy); + bulletAppState.getPhysicsSpace().add(floor_phy); + } + + /** This loop builds a wall out of individual bricks. */ + public void initWall() { + float startpt = brickLength / 4; + float height = 0; + for (int j = 0; j < 15; j++) { + for (int i = 0; i < 6; i++) { + Vector3f vt = + new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0); + makeBrick(vt); + } + startpt = -startpt; + height += 2 * brickHeight; + } + } + + /** This method creates one individual physical brick. */ + public void makeBrick(Vector3f loc) { + /** Create a brick geometry and attach to scene graph. */ + Geometry brick_geo = new Geometry("brick", box); + brick_geo.setMaterial(wall_mat); + rootNode.attachChild(brick_geo); + /** Position the brick geometry */ + brick_geo.setLocalTranslation(loc); + /** Make brick physical with a mass > 0.0f. */ + brick_phy = new RigidBodyControl(2f); + /** Add physical brick to physics space. */ + brick_geo.addControl(brick_phy); + bulletAppState.getPhysicsSpace().add(brick_phy); + } + + /** This method creates one individual physical cannon ball. + * By defaul, the ball is accelerated and flies + * from the camera position in the camera direction.*/ + public void makeCannonBall() { + /** Create a cannon ball geometry and attach to scene graph. */ + Geometry ball_geo = new Geometry("cannon ball", sphere); + ball_geo.setMaterial(stone_mat); + rootNode.attachChild(ball_geo); + /** Position the cannon ball */ + ball_geo.setLocalTranslation(cam.getLocation()); + /** Make the ball physical with a mass > 0.0f */ + ball_phy = new RigidBodyControl(1f); + /** Add physical ball to physics space. */ + ball_geo.addControl(ball_phy); + bulletAppState.getPhysicsSpace().add(ball_phy); + /** Accelerate the physical ball to shoot it. */ + ball_phy.setLinearVelocity(cam.getDirection().mult(25)); + } + + /** A plus sign used as crosshairs to help the player with aiming.*/ + protected void initCrossHairs() { + setDisplayStatView(false); + //guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // fake crosshairs :) + ch.setLocalTranslation( // center + settings.getWidth() / 2, + settings.getHeight() / 2, 0); + guiNode.attachChild(ch); + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloPicking.java b/JmeTests/src/jme3test/helloworld/HelloPicking.java new file mode 100644 index 0000000..caee4f9 --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloPicking.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Ray; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; + +/** Sample 8 - how to let the user pick (select) objects in the scene + * using the mouse or key presses. Can be used for shooting, opening doors, etc. */ +public class HelloPicking extends SimpleApplication { + + public static void main(String[] args) { + HelloPicking app = new HelloPicking(); + app.start(); + } + private Node shootables; + private Geometry mark; + + @Override + public void simpleInitApp() { + initCrossHairs(); // a "+" in the middle of the screen to help aiming + initKeys(); // load custom key mappings + initMark(); // a red sphere to mark the hit + + /** create four colored boxes and a floor to shoot at: */ + shootables = new Node("Shootables"); + rootNode.attachChild(shootables); + shootables.attachChild(makeCube("a Dragon", -2f, 0f, 1f)); + shootables.attachChild(makeCube("a tin can", 1f, -2f, 0f)); + shootables.attachChild(makeCube("the Sheriff", 0f, 1f, -2f)); + shootables.attachChild(makeCube("the Deputy", 1f, 0f, -4f)); + shootables.attachChild(makeFloor()); + shootables.attachChild(makeCharacter()); + } + + /** Declaring the "Shoot" action and mapping to its triggers. */ + private void initKeys() { + inputManager.addMapping("Shoot", + new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar + new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click + inputManager.addListener(actionListener, "Shoot"); + } + /** Defining the "Shoot" action: Determine what was hit and how to respond. */ + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("Shoot") && !keyPressed) { + // 1. Reset results list. + CollisionResults results = new CollisionResults(); + // 2. Aim the ray from cam loc to cam direction. + Ray ray = new Ray(cam.getLocation(), cam.getDirection()); + // 3. Collect intersections between Ray and Shootables in results list. + shootables.collideWith(ray, results); + // 4. Print the results + System.out.println("----- Collisions? " + results.size() + "-----"); + for (int i = 0; i < results.size(); i++) { + // For each hit, we know distance, impact point, name of geometry. + float dist = results.getCollision(i).getDistance(); + Vector3f pt = results.getCollision(i).getContactPoint(); + String hit = results.getCollision(i).getGeometry().getName(); + System.out.println("* Collision #" + i); + System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away."); + } + // 5. Use the results (we mark the hit object) + if (results.size() > 0) { + // The closest collision point is what was truly hit: + CollisionResult closest = results.getClosestCollision(); + // Let's interact - we mark the hit with a red dot. + mark.setLocalTranslation(closest.getContactPoint()); + rootNode.attachChild(mark); + } else { + // No hits? Then remove the red mark. + rootNode.detachChild(mark); + } + } + } + }; + + /** A cube object for target practice */ + protected Geometry makeCube(String name, float x, float y, float z) { + Box box = new Box(1, 1, 1); + Geometry cube = new Geometry(name, box); + cube.setLocalTranslation(x, y, z); + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.randomColor()); + cube.setMaterial(mat1); + return cube; + } + + /** A floor to show that the "shot" can go through several objects. */ + protected Geometry makeFloor() { + Box box = new Box(15, .2f, 15); + Geometry floor = new Geometry("the Floor", box); + floor.setLocalTranslation(0, -4, -5); + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setColor("Color", ColorRGBA.Gray); + floor.setMaterial(mat1); + return floor; + } + + /** A red ball that marks the last spot that was "hit" by the "shot". */ + protected void initMark() { + Sphere sphere = new Sphere(30, 30, 0.2f); + mark = new Geometry("BOOM!", sphere); + Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mark_mat.setColor("Color", ColorRGBA.Red); + mark.setMaterial(mark_mat); + } + + /** A centred plus sign to help the player aim. */ + protected void initCrossHairs() { + setDisplayStatView(false); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - ch.getLineWidth()/2, settings.getHeight() / 2 + ch.getLineHeight()/2, 0); + guiNode.attachChild(ch); + } + + protected Spatial makeCharacter() { + // load a character from jme3test-test-data + Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + golem.scale(0.5f); + golem.setLocalTranslation(-1.0f, -1.5f, -0.6f); + + // We must add a light to make the model visible + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f)); + golem.addLight(sun); + return golem; + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloTerrain.java b/JmeTests/src/jme3test/helloworld/HelloTerrain.java new file mode 100644 index 0000000..69b8caf --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloTerrain.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + +public class HelloTerrain extends SimpleApplication { + + private TerrainQuad terrain; + Material mat_terrain; + + public static void main(String[] args) { + HelloTerrain app = new HelloTerrain(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(50); + + /** 1. Create terrain material and load four textures into it. */ + mat_terrain = new Material(assetManager, + "Common/MatDefs/Terrain/Terrain.j3md"); + + /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */ + mat_terrain.setTexture("Alpha", assetManager.loadTexture( + "Textures/Terrain/splat/alphamap.png")); + + /** 1.2) Add GRASS texture into the red layer (Tex1). */ + Texture grass = assetManager.loadTexture( + "Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex1", grass); + mat_terrain.setFloat("Tex1Scale", 64f); + + /** 1.3) Add DIRT texture into the green layer (Tex2) */ + Texture dirt = assetManager.loadTexture( + "Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex2", dirt); + mat_terrain.setFloat("Tex2Scale", 32f); + + /** 1.4) Add ROAD texture into the blue layer (Tex3) */ + Texture rock = assetManager.loadTexture( + "Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex3", rock); + mat_terrain.setFloat("Tex3Scale", 128f); + + /** 2.a Create a custom height map from an image */ + AbstractHeightMap heightmap = null; + Texture heightMapImage = assetManager.loadTexture( + "Textures/Terrain/splat/mountains512.png"); + heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); + +/** 2.b Create a random height map */ +// HillHeightMap heightmap = null; +// HillHeightMap.NORMALIZE_RANGE = 100; +// try { +// heightmap = new HillHeightMap(513, 1000, 50, 100, (byte) 3); +// } catch (Exception ex) { +// ex.printStackTrace(); +// } + + heightmap.load(); + + /** 3. We have prepared material and heightmap. + * Now we create the actual terrain: + * 3.1) Create a TerrainQuad and name it "my terrain". + * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65. + * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513. + * 3.4) As LOD step scale we supply Vector3f(1,1,1). + * 3.5) We supply the prepared heightmap itself. + */ + int patchSize = 65; + terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap()); + + /** 4. We give the terrain its material, position & scale it, and attach it. */ + terrain.setMaterial(mat_terrain); + terrain.setLocalTranslation(0, -100, 0); + terrain.setLocalScale(2f, 1f, 2f); + rootNode.attachChild(terrain); + + /** 5. The LOD (level of detail) depends on were the camera is: */ + TerrainLodControl control = new TerrainLodControl(terrain, getCamera()); + control.setLodCalculator( new DistanceLodCalculator(patchSize, 2.7f) ); // patch size, and a multiplier + terrain.addControl(control); + } +} diff --git a/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java b/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java new file mode 100644 index 0000000..d7ea68f --- /dev/null +++ b/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.helloworld; + +import com.jme3.app.SimpleApplication; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import java.util.ArrayList; +import java.util.List; + +/** + * This demo shows a terrain with collision detection, + * that you can walk around in with a first-person perspective. + * This code combines HelloCollision and HelloTerrain. + */ +public class HelloTerrainCollision extends SimpleApplication + implements ActionListener { + + private BulletAppState bulletAppState; + private RigidBodyControl landscape; + private CharacterControl player; + private Vector3f walkDirection = new Vector3f(); + private boolean left = false, right = false, up = false, down = false; + private TerrainQuad terrain; + private Material mat_terrain; + //Temporary vectors used on each frame. + //They here to avoid instanciating new vectors on each frame + private Vector3f camDir = new Vector3f(); + private Vector3f camLeft = new Vector3f(); + + public static void main(String[] args) { + HelloTerrainCollision app = new HelloTerrainCollision(); + app.start(); + } + + @Override + public void simpleInitApp() { + /** Set up Physics */ + bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + //bulletAppState.getPhysicsSpace().enableDebug(assetManager); + + flyCam.setMoveSpeed(100); + setUpKeys(); + + /** 1. Create terrain material and load four textures into it. */ + mat_terrain = new Material(assetManager, + "Common/MatDefs/Terrain/Terrain.j3md"); + + /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */ + mat_terrain.setTexture("Alpha", assetManager.loadTexture( + "Textures/Terrain/splat/alphamap.png")); + + /** 1.2) Add GRASS texture into the red layer (Tex1). */ + Texture grass = assetManager.loadTexture( + "Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex1", grass); + mat_terrain.setFloat("Tex1Scale", 64f); + + /** 1.3) Add DIRT texture into the green layer (Tex2) */ + Texture dirt = assetManager.loadTexture( + "Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex2", dirt); + mat_terrain.setFloat("Tex2Scale", 32f); + + /** 1.4) Add ROAD texture into the blue layer (Tex3) */ + Texture rock = assetManager.loadTexture( + "Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + mat_terrain.setTexture("Tex3", rock); + mat_terrain.setFloat("Tex3Scale", 128f); + + /** 2. Create the height map */ + AbstractHeightMap heightmap = null; + Texture heightMapImage = assetManager.loadTexture( + "Textures/Terrain/splat/mountains512.png"); + heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); + heightmap.load(); + + /** 3. We have prepared material and heightmap. + * Now we create the actual terrain: + * 3.1) Create a TerrainQuad and name it "my terrain". + * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65. + * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513. + * 3.4) As LOD step scale we supply Vector3f(1,1,1). + * 3.5) We supply the prepared heightmap itself. + */ + terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap()); + + /** 4. We give the terrain its material, position & scale it, and attach it. */ + terrain.setMaterial(mat_terrain); + terrain.setLocalTranslation(0, -100, 0); + terrain.setLocalScale(2f, 1f, 2f); + rootNode.attachChild(terrain); + + /** 5. The LOD (level of detail) depends on were the camera is: */ + List cameras = new ArrayList(); + cameras.add(getCamera()); + TerrainLodControl control = new TerrainLodControl(terrain, cameras); + terrain.addControl(control); + + /** 6. Add physics: */ + /* We set up collision detection for the scene by creating a static + * RigidBodyControl with mass zero.*/ + terrain.addControl(new RigidBodyControl(0)); + + // We set up collision detection for the player by creating + // a capsule collision shape and a CharacterControl. + // The CharacterControl offers extra settings for + // size, stepheight, jumping, falling, and gravity. + // We also put the player in its starting position. + CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1); + player = new CharacterControl(capsuleShape, 0.05f); + player.setJumpSpeed(20); + player.setFallSpeed(30); + player.setGravity(30); + player.setPhysicsLocation(new Vector3f(-10, 10, 10)); + + // We attach the scene and the player to the rootnode and the physics space, + // to make them appear in the game world. + bulletAppState.getPhysicsSpace().add(terrain); + bulletAppState.getPhysicsSpace().add(player); + + } + /** We over-write some navigational key mappings here, so we can + * add physics-controlled walking and jumping: */ + private void setUpKeys() { + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, "Left"); + inputManager.addListener(this, "Right"); + inputManager.addListener(this, "Up"); + inputManager.addListener(this, "Down"); + inputManager.addListener(this, "Jump"); + } + + /** These are our custom actions triggered by key presses. + * We do not walk yet, we just keep track of the direction the user pressed. */ + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Left")) { + if (value) { left = true; } else { left = false; } + } else if (binding.equals("Right")) { + if (value) { right = true; } else { right = false; } + } else if (binding.equals("Up")) { + if (value) { up = true; } else { up = false; } + } else if (binding.equals("Down")) { + if (value) { down = true; } else { down = false; } + } else if (binding.equals("Jump")) { + player.jump(); + } + } + + /** + * This is the main event loop--walking happens here. + * We check in which direction the player is walking by interpreting + * the camera direction forward (camDir) and to the side (camLeft). + * The setWalkDirection() command is what lets a physics-controlled player walk. + * We also make sure here that the camera moves with player. + */ + @Override + public void simpleUpdate(float tpf) { + camDir.set(cam.getDirection()).multLocal(0.6f); + camLeft.set(cam.getLeft()).multLocal(0.4f); + walkDirection.set(0, 0, 0); + if (left) { + walkDirection.addLocal(camLeft); + } + if (right) { + walkDirection.addLocal(camLeft.negate()); + } + if (up) { + walkDirection.addLocal(camDir); + } + if (down) { + walkDirection.addLocal(camDir.negate()); + } + player.setWalkDirection(walkDirection); + cam.setLocation(player.getPhysicsLocation()); + } +} + diff --git a/JmeTests/src/jme3test/input/TestCameraNode.java b/JmeTests/src/jme3test/input/TestCameraNode.java new file mode 100644 index 0000000..c1ebfeb --- /dev/null +++ b/JmeTests/src/jme3test/input/TestCameraNode.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved. + *

+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + *

+ * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + *

+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.input; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.*; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.CameraNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.CameraControl.ControlDirection; +import com.jme3.scene.shape.Quad; +import com.jme3.system.AppSettings; + +/** + * A 3rd-person camera node follows a target (teapot). Follow the teapot with + * WASD keys, rotate by dragging the mouse. + */ +public class TestCameraNode extends SimpleApplication implements AnalogListener, ActionListener { + + private Geometry teaGeom; + private Node teaNode; + CameraNode camNode; + boolean rotate = false; + Vector3f direction = new Vector3f(); + + public static void main(String[] args) { + TestCameraNode app = new TestCameraNode(); + AppSettings s = new AppSettings(true); + s.setFrameRate(100); + app.setSettings(s); + app.start(); + } + + public void simpleInitApp() { + // load a teapot model + teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + teaGeom.setMaterial(mat); + //create a node to attach the geometry and the camera node + teaNode = new Node("teaNode"); + teaNode.attachChild(teaGeom); + rootNode.attachChild(teaNode); + // create a floor + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Geometry ground = new Geometry("ground", new Quad(50, 50)); + ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + ground.setLocalTranslation(-25, -1, 25); + ground.setMaterial(mat); + rootNode.attachChild(ground); + + //creating the camera Node + camNode = new CameraNode("CamNode", cam); + //Setting the direction to Spatial to camera, this means the camera will copy the movements of the Node + camNode.setControlDir(ControlDirection.SpatialToCamera); + //attaching the camNode to the teaNode + teaNode.attachChild(camNode); + //setting the local translation of the cam node to move it away from the teanNode a bit + camNode.setLocalTranslation(new Vector3f(-10, 0, 0)); + //setting the camNode to look at the teaNode + camNode.lookAt(teaNode.getLocalTranslation(), Vector3f.UNIT_Y); + + //disable the default 1st-person flyCam (don't forget this!!) + flyCam.setEnabled(false); + + registerInput(); + } + + public void registerInput() { + inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W)); + inputManager.addMapping("moveBackward", new KeyTrigger(keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S)); + inputManager.addMapping("moveRight", new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(keyInput.KEY_D)); + inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT), new KeyTrigger(keyInput.KEY_A)); + inputManager.addMapping("toggleRotate", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addMapping("rotateRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); + inputManager.addMapping("rotateLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); + inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft"); + inputManager.addListener(this, "rotateRight", "rotateLeft", "toggleRotate"); + } + + public void onAnalog(String name, float value, float tpf) { + //computing the normalized direction of the cam to move the teaNode + direction.set(cam.getDirection()).normalizeLocal(); + if (name.equals("moveForward")) { + direction.multLocal(5 * tpf); + teaNode.move(direction); + } + if (name.equals("moveBackward")) { + direction.multLocal(-5 * tpf); + teaNode.move(direction); + } + if (name.equals("moveRight")) { + direction.crossLocal(Vector3f.UNIT_Y).multLocal(5 * tpf); + teaNode.move(direction); + } + if (name.equals("moveLeft")) { + direction.crossLocal(Vector3f.UNIT_Y).multLocal(-5 * tpf); + teaNode.move(direction); + } + if (name.equals("rotateRight") && rotate) { + teaNode.rotate(0, 5 * tpf, 0); + } + if (name.equals("rotateLeft") && rotate) { + teaNode.rotate(0, -5 * tpf, 0); + } + + } + + public void onAction(String name, boolean keyPressed, float tpf) { + //toggling rotation on or off + if (name.equals("toggleRotate") && keyPressed) { + rotate = true; + inputManager.setCursorVisible(false); + } + if (name.equals("toggleRotate") && !keyPressed) { + rotate = false; + inputManager.setCursorVisible(true); + } + + } +} diff --git a/JmeTests/src/jme3test/input/TestChaseCamera.java b/JmeTests/src/jme3test/input/TestChaseCamera.java new file mode 100644 index 0000000..d933f96 --- /dev/null +++ b/JmeTests/src/jme3test/input/TestChaseCamera.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.input; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.ChaseCamera; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +/** A 3rd-person chase camera orbits a target (teapot). + * Follow the teapot with WASD keys, rotate by dragging the mouse. */ +public class TestChaseCamera extends SimpleApplication implements AnalogListener, ActionListener { + + private Geometry teaGeom; + private ChaseCamera chaseCam; + + public static void main(String[] args) { + TestChaseCamera app = new TestChaseCamera(); + app.start(); + } + + public void simpleInitApp() { + // Load a teapot model + teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + Material mat_tea = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + teaGeom.setMaterial(mat_tea); + rootNode.attachChild(teaGeom); + + // Load a floor model + Material mat_ground = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat_ground.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Geometry ground = new Geometry("ground", new Quad(50, 50)); + ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + ground.setLocalTranslation(-25, -1, 25); + ground.setMaterial(mat_ground); + rootNode.attachChild(ground); + + // Disable the default first-person cam! + flyCam.setEnabled(false); + + // Enable a chase cam + chaseCam = new ChaseCamera(cam, teaGeom, inputManager); + + //Uncomment this to invert the camera's vertical rotation Axis + //chaseCam.setInvertVerticalAxis(true); + + //Uncomment this to invert the camera's horizontal rotation Axis + //chaseCam.setInvertHorizontalAxis(true); + + //Comment this to disable smooth camera motion + chaseCam.setSmoothMotion(true); + + //Uncomment this to disable trailing of the camera + //WARNING, trailing only works with smooth motion enabled. It is true by default. + //chaseCam.setTrailingEnabled(false); + + //Uncomment this to look 3 world units above the target + //chaseCam.setLookAtOffset(Vector3f.UNIT_Y.mult(3)); + + //Uncomment this to enable rotation when the middle mouse button is pressed (like Blender) + //WARNING : setting this trigger disable the rotation on right and left mouse button click + //chaseCam.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); + + //Uncomment this to set multiple triggers to enable rotation of the cam + //Here spade bar and middle mouse button + //chaseCam.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE),new KeyTrigger(KeyInput.KEY_SPACE)); + + //registering inputs for target's movement + registerInput(); + + } + + public void registerInput() { + inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W)); + inputManager.addMapping("moveBackward", new KeyTrigger(keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S)); + inputManager.addMapping("moveRight", new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(keyInput.KEY_D)); + inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT), new KeyTrigger(keyInput.KEY_A)); + inputManager.addMapping("displayPosition", new KeyTrigger(keyInput.KEY_P)); + inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft"); + inputManager.addListener(this, "displayPosition"); + } + + public void onAnalog(String name, float value, float tpf) { + if (name.equals("moveForward")) { + teaGeom.move(0, 0, -5 * tpf); + } + if (name.equals("moveBackward")) { + teaGeom.move(0, 0, 5 * tpf); + } + if (name.equals("moveRight")) { + teaGeom.move(5 * tpf, 0, 0); + } + if (name.equals("moveLeft")) { + teaGeom.move(-5 * tpf, 0, 0); + + } + + } + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("displayPosition") && keyPressed) { + teaGeom.move(10, 10, 10); + + } + } + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + + // teaGeom.move(new Vector3f(0.001f, 0, 0)); + // pivot.rotate(0, 0.00001f, 0); + // rootNode.updateGeometricState(); + } +// public void update() { +// super.update(); +//// render the viewports +// float tpf = timer.getTimePerFrame(); +// state.getRootNode().rotate(0, 0.000001f, 0); +// stateManager.update(tpf); +// stateManager.render(renderManager); +// renderManager.render(tpf); +// } +} diff --git a/JmeTests/src/jme3test/input/TestChaseCameraAppState.java b/JmeTests/src/jme3test/input/TestChaseCameraAppState.java new file mode 100644 index 0000000..00d6dd8 --- /dev/null +++ b/JmeTests/src/jme3test/input/TestChaseCameraAppState.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.input; + +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.FlyCamAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +/** A 3rd-person chase camera orbits a target (teapot). + * Follow the teapot with WASD keys, rotate by dragging the mouse. */ +public class TestChaseCameraAppState extends SimpleApplication implements AnalogListener, ActionListener { + + private Geometry teaGeom; + + public static void main(String[] args) { + TestChaseCameraAppState app = new TestChaseCameraAppState(); + app.start(); + } + + public void simpleInitApp() { + // Load a teapot model + teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + Material mat_tea = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + teaGeom.setMaterial(mat_tea); + rootNode.attachChild(teaGeom); + + // Load a floor model + Material mat_ground = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat_ground.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Geometry ground = new Geometry("ground", new Quad(50, 50)); + ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + ground.setLocalTranslation(-25, -1, 25); + ground.setMaterial(mat_ground); + rootNode.attachChild(ground); + + //disable the flyCam + stateManager.detach(stateManager.getState(FlyCamAppState.class)); + + // Enable a chase cam + ChaseCameraAppState chaseCamAS = new ChaseCameraAppState(); + chaseCamAS.setTarget(teaGeom); + stateManager.attach(chaseCamAS); + + //Uncomment this to invert the camera's vertical rotation Axis + //chaseCamAS.setInvertVerticalAxis(true); + + //Uncomment this to invert the camera's horizontal rotation Axis + //chaseCamAS.setInvertHorizontalAxis(true); + + //Uncomment this to enable rotation when the middle mouse button is pressed (like Blender) + //WARNING : setting this trigger disable the rotation on right and left mouse button click + //chaseCamAS.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); + + //Uncomment this to set multiple triggers to enable rotation of the cam + //Here space bar and middle mouse button + //chaseCamAS.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE),new KeyTrigger(KeyInput.KEY_SPACE)); + + //registering inputs for target's movement + registerInput(); + + } + + public void registerInput() { + inputManager.addMapping("moveForward", new KeyTrigger(KeyInput.KEY_UP), new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("moveBackward", new KeyTrigger(KeyInput.KEY_DOWN), new KeyTrigger(KeyInput.KEY_S)); + inputManager.addMapping("moveRight", new KeyTrigger(KeyInput.KEY_RIGHT), new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("moveLeft", new KeyTrigger(KeyInput.KEY_LEFT), new KeyTrigger(KeyInput.KEY_A)); + inputManager.addMapping("displayPosition", new KeyTrigger(KeyInput.KEY_P)); + inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft"); + inputManager.addListener(this, "displayPosition"); + } + + public void onAnalog(String name, float value, float tpf) { + if (name.equals("moveForward")) { + teaGeom.move(0, 0, -5 * tpf); + } + if (name.equals("moveBackward")) { + teaGeom.move(0, 0, 5 * tpf); + } + if (name.equals("moveRight")) { + teaGeom.move(5 * tpf, 0, 0); + } + if (name.equals("moveLeft")) { + teaGeom.move(-5 * tpf, 0, 0); + + } + + } + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("displayPosition") && keyPressed) { + teaGeom.move(10, 10, 10); + + } + } + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + + // teaGeom.move(new Vector3f(0.001f, 0, 0)); + // pivot.rotate(0, 0.00001f, 0); + // rootNode.updateGeometricState(); + } +// public void update() { +// super.update(); +//// render the viewports +// float tpf = timer.getTimePerFrame(); +// state.getRootNode().rotate(0, 0.000001f, 0); +// stateManager.update(tpf); +// stateManager.render(renderManager); +// renderManager.render(tpf); +// } +} diff --git a/JmeTests/src/jme3test/input/TestControls.java b/JmeTests/src/jme3test/input/TestControls.java new file mode 100644 index 0000000..07568b2 --- /dev/null +++ b/JmeTests/src/jme3test/input/TestControls.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.input; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseAxisTrigger; + +public class TestControls extends SimpleApplication { + + private ActionListener actionListener = new ActionListener(){ + public void onAction(String name, boolean pressed, float tpf){ + System.out.println(name + " = " + pressed); + } + }; + public AnalogListener analogListener = new AnalogListener() { + public void onAnalog(String name, float value, float tpf) { + System.out.println(name + " = " + value); + } + }; + + public static void main(String[] args){ + TestControls app = new TestControls(); + app.start(); + } + + @Override + public void simpleInitApp() { + // Test multiple inputs per mapping + inputManager.addMapping("My Action", + new KeyTrigger(KeyInput.KEY_SPACE), + new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); + + // Test multiple listeners per mapping + inputManager.addListener(actionListener, "My Action"); + inputManager.addListener(analogListener, "My Action"); + } + +} diff --git a/JmeTests/src/jme3test/input/TestJoystick.java b/JmeTests/src/jme3test/input/TestJoystick.java new file mode 100644 index 0000000..29a9166 --- /dev/null +++ b/JmeTests/src/jme3test/input/TestJoystick.java @@ -0,0 +1,443 @@ +package jme3test.input; + +import com.jme3.app.SimpleApplication; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.font.BitmapText; +import com.jme3.input.Joystick; +import com.jme3.input.JoystickAxis; +import com.jme3.input.JoystickButton; +import com.jme3.input.RawInputListener; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Ray; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Quad; +import com.jme3.system.AppSettings; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +public class TestJoystick extends SimpleApplication { + + private Joystick viewedJoystick; + private GamepadView gamepad; + private Node joystickInfo; + private float yInfo = 0; + private JoystickButton lastButton; + + public static void main(String[] args){ + TestJoystick app = new TestJoystick(); + AppSettings settings = new AppSettings(true); + settings.setUseJoysticks(true); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + getFlyByCamera().setEnabled(false); + + Joystick[] joysticks = inputManager.getJoysticks(); + if (joysticks == null) + throw new IllegalStateException("Cannot find any joysticks!"); + + try { + PrintWriter out = new PrintWriter( new FileWriter( "joysticks-" + System.currentTimeMillis() + ".txt" ) ); + dumpJoysticks( joysticks, out ); + out.close(); + } catch( IOException e ) { + throw new RuntimeException( "Error writing joystick dump", e ); + } + + + int gamepadSize = cam.getHeight() / 2; + float scale = gamepadSize / 512.0f; + gamepad = new GamepadView(); + gamepad.setLocalTranslation( cam.getWidth() - gamepadSize - (scale * 20), 0, 0 ); + gamepad.setLocalScale( scale, scale, scale ); + guiNode.attachChild(gamepad); + + joystickInfo = new Node( "joystickInfo" ); + joystickInfo.setLocalTranslation( 0, cam.getHeight(), 0 ); + guiNode.attachChild( joystickInfo ); + + // Add a raw listener because it's eisier to get all joystick events + // this way. + inputManager.addRawInputListener( new JoystickEventListener() ); + + // add action listener for mouse click + // to all easier custom mapping + inputManager.addMapping("mouseClick", new MouseButtonTrigger(mouseInput.BUTTON_LEFT)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed){ + pickGamePad(getInputManager().getCursorPosition()); + } + } + }, "mouseClick"); + } + + protected void dumpJoysticks( Joystick[] joysticks, PrintWriter out ) { + for( Joystick j : joysticks ) { + out.println( "Joystick[" + j.getJoyId() + "]:" + j.getName() ); + out.println( " buttons:" + j.getButtonCount() ); + for( JoystickButton b : j.getButtons() ) { + out.println( " " + b ); + } + + out.println( " axes:" + j.getAxisCount() ); + for( JoystickAxis axis : j.getAxes() ) { + out.println( " " + axis ); + } + } + } + + protected void addInfo( String info, int column ) { + + BitmapText t = new BitmapText(guiFont); + t.setText( info ); + t.setLocalTranslation( column * 200, yInfo, 0 ); + joystickInfo.attachChild(t); + yInfo -= t.getHeight(); + } + + protected void setViewedJoystick( Joystick stick ) { + if( this.viewedJoystick == stick ) + return; + + if( this.viewedJoystick != null ) { + joystickInfo.detachAllChildren(); + } + + this.viewedJoystick = stick; + + if( this.viewedJoystick != null ) { + // Draw the hud + yInfo = 0; + + addInfo( "Joystick:\"" + stick.getName() + "\" id:" + stick.getJoyId(), 0 ); + + yInfo -= 5; + + float ySave = yInfo; + + // Column one for the buttons + addInfo( "Buttons:", 0 ); + for( JoystickButton b : stick.getButtons() ) { + addInfo( " '" + b.getName() + "' id:'" + b.getLogicalId() + "'", 0 ); + } + yInfo = ySave; + + // Column two for the axes + addInfo( "Axes:", 1 ); + for( JoystickAxis a : stick.getAxes() ) { + addInfo( " '" + a.getName() + "' id:'" + a.getLogicalId() + "' analog:" + a.isAnalog(), 1 ); + } + + } + } + + /** + * Easier to watch for all button and axis events with a raw input listener. + */ + protected class JoystickEventListener implements RawInputListener { + + public void onJoyAxisEvent(JoyAxisEvent evt) { + setViewedJoystick( evt.getAxis().getJoystick() ); + gamepad.setAxisValue( evt.getAxis(), evt.getValue() ); + } + + public void onJoyButtonEvent(JoyButtonEvent evt) { + setViewedJoystick( evt.getButton().getJoystick() ); + gamepad.setButtonValue( evt.getButton(), evt.isPressed() ); + } + + public void beginInput() {} + public void endInput() {} + public void onMouseMotionEvent(MouseMotionEvent evt) {} + public void onMouseButtonEvent(MouseButtonEvent evt) {} + public void onKeyEvent(KeyInputEvent evt) {} + public void onTouchEvent(TouchEvent evt) {} + } + + protected class GamepadView extends Node { + + float xAxis = 0; + float yAxis = 0; + float zAxis = 0; + float zRotation = 0; + + float lastPovX = 0; + float lastPovY = 0; + + Geometry leftStick; + Geometry rightStick; + + Map buttons = new HashMap(); + + public GamepadView() { + super( "gamepad" ); + + // Sizes naturally for the texture size. All positions will + // be in that space because it's easier. + int size = 512; + + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-buttons.png" ) ); + m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha ); + Geometry buttonPanel = new Geometry( "buttons", new Quad(size, size) ); + buttonPanel.setLocalTranslation( 0, 0, -1 ); + buttonPanel.setMaterial(m); + attachChild(buttonPanel); + + m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-frame.png" ) ); + m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha ); + Geometry frame = new Geometry( "frame", new Quad(size, size) ); + frame.setMaterial(m); + attachChild(frame); + + m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-stick.png" ) ); + m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha ); + leftStick = new Geometry( "leftStick", new Quad(64, 64) ); + leftStick.setMaterial(m); + attachChild(leftStick); + rightStick = new Geometry( "rightStick", new Quad(64, 64) ); + rightStick.setMaterial(m); + attachChild(rightStick); + + // A "standard" mapping... fits a majority of my game pads + addButton( JoystickButton.BUTTON_0, 371, 512 - 176, 42, 42 ); + addButton( JoystickButton.BUTTON_1, 407, 512 - 212, 42, 42 ); + addButton( JoystickButton.BUTTON_2, 371, 512 - 248, 42, 42 ); + addButton( JoystickButton.BUTTON_3, 334, 512 - 212, 42, 42 ); + + // Front buttons Some of these have the top ones and the bottoms ones flipped. + addButton( JoystickButton.BUTTON_4, 67, 512 - 111, 95, 21 ); + addButton( JoystickButton.BUTTON_5, 348, 512 - 111, 95, 21 ); + addButton( JoystickButton.BUTTON_6, 67, 512 - 89, 95, 21 ); + addButton( JoystickButton.BUTTON_7, 348, 512 - 89, 95, 21 ); + + // Select and start buttons + addButton( JoystickButton.BUTTON_8, 206, 512 - 198, 48, 30 ); + addButton( JoystickButton.BUTTON_9, 262, 512 - 198, 48, 30 ); + + // Joystick push buttons + addButton( JoystickButton.BUTTON_10, 147, 512 - 300, 75, 70 ); + addButton( JoystickButton.BUTTON_11, 285, 512 - 300, 75, 70 ); + + // Fake button highlights for the POV axes + // + // +Y + // -X +X + // -Y + // + addButton( "POV +Y", 96, 512 - 174, 40, 38 ); + addButton( "POV +X", 128, 512 - 208, 40, 38 ); + addButton( "POV -Y", 96, 512 - 239, 40, 38 ); + addButton( "POV -X", 65, 512 - 208, 40, 38 ); + + resetPositions(); + } + + private void addButton( String name, float x, float y, float width, float height ) { + ButtonView b = new ButtonView(name, x, y, width, height); + attachChild(b); + buttons.put(name, b); + } + + public void setAxisValue( JoystickAxis axis, float value ) { + System.out.println( "Axis:" + axis.getName() + "=" + value ); + if( axis == axis.getJoystick().getXAxis() ) { + setXAxis(value); + } else if( axis == axis.getJoystick().getYAxis() ) { + setYAxis(-value); + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_AXIS) ) { + // Note: in the above condition, we could check the axis name but + // I have at least one joystick that reports 2 "Z Axis" axes. + // In this particular case, the first one is the right one so + // a name based lookup will find the proper one. It's a problem + // because the erroneous axis sends a constant stream of values. + setZAxis(value); + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_ROTATION) ) { + setZRotation(-value); + } else if( axis == axis.getJoystick().getPovXAxis() ) { + if( lastPovX < 0 ) { + setButtonValue( "POV -X", false ); + } else if( lastPovX > 0 ) { + setButtonValue( "POV +X", false ); + } + if( value < 0 ) { + setButtonValue( "POV -X", true ); + } else if( value > 0 ) { + setButtonValue( "POV +X", true ); + } + lastPovX = value; + } else if( axis == axis.getJoystick().getPovYAxis() ) { + if( lastPovY < 0 ) { + setButtonValue( "POV -Y", false ); + } else if( lastPovY > 0 ) { + setButtonValue( "POV +Y", false ); + } + if( value < 0 ) { + setButtonValue( "POV -Y", true ); + } else if( value > 0 ) { + setButtonValue( "POV +Y", true ); + } + lastPovY = value; + } + } + + public void setButtonValue( JoystickButton button, boolean isPressed ) { + System.out.println( "Button:" + button.getName() + "=" + (isPressed ? "Down" : "Up") ); + setButtonValue( button.getLogicalId(), isPressed ); + lastButton = button; + } + + protected void setButtonValue( String name, boolean isPressed ) { + ButtonView view = buttons.get(name); + if( view != null ) { + if( isPressed ) { + view.down(); + } else { + view.up(); + } + } + } + + public void setXAxis( float f ) { + xAxis = f; + resetPositions(); + } + + public void setYAxis( float f ) { + yAxis = f; + resetPositions(); + } + + public void setZAxis( float f ) { + zAxis = f; + resetPositions(); + } + + public void setZRotation( float f ) { + zRotation = f; + resetPositions(); + } + + private void resetPositions() { + + float xBase = 155; + float yBase = 212; + + Vector2f dir = new Vector2f(xAxis, yAxis); + float length = Math.min(1, dir.length()); + dir.normalizeLocal(); + + float angle = dir.getAngle(); + float x = FastMath.cos(angle) * length * 10; + float y = FastMath.sin(angle) * length * 10; + leftStick.setLocalTranslation( xBase + x, yBase + y, 0 ); + + + xBase = 291; + dir = new Vector2f(zAxis, zRotation); + length = Math.min(1, dir.length()); + dir.normalizeLocal(); + + angle = dir.getAngle(); + x = FastMath.cos(angle) * length * 10; + y = FastMath.sin(angle) * length * 10; + rightStick.setLocalTranslation( xBase + x, yBase + y, 0 ); + } + } + + protected class ButtonView extends Node { + + private int state = 0; + private Material material; + private ColorRGBA hilite = new ColorRGBA( 0.0f, 0.75f, 0.75f, 0.5f ); + + public ButtonView( String name, float x, float y, float width, float height ) { + super( "Button:" + name ); + setLocalTranslation( x, y, -0.5f ); + + material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor( "Color", hilite ); + material.getAdditionalRenderState().setBlendMode( BlendMode.Alpha ); + + Geometry g = new Geometry( "highlight", new Quad(width, height) ); + g.setMaterial(material); + attachChild(g); + + resetState(); + } + + private void resetState() { + if( state <= 0 ) { + setCullHint( CullHint.Always ); + } else { + setCullHint( CullHint.Dynamic ); + } + + System.out.println( getName() + " state:" + state ); + } + + public void down() { + state++; + resetState(); + } + + public void up() { + state--; + resetState(); + } + } + + private void pickGamePad(Vector2f mouseLoc){ + if (lastButton != null) { + CollisionResults cresults = pick(cam, mouseLoc, gamepad); + for (CollisionResult cr : cresults) { + Node n = cr.getGeometry().getParent(); + if (n != null && (n instanceof ButtonView)) { + String b = ((ButtonView) n).getName().substring("Button:".length()); + String name = lastButton.getJoystick().getName().replaceAll(" ", "\\\\ "); + String id = lastButton.getLogicalId().replaceAll(" ", "\\\\ "); + System.out.println(name + "." + id + "=" + b); + return; + } + } + } + } + + private static CollisionResults pick(Camera cam, Vector2f mouseLoc, Node node) { + CollisionResults results = new CollisionResults(); + Ray ray = new Ray(); + Vector3f pos = new Vector3f(mouseLoc.x, mouseLoc.y, -1); + Vector3f dir = new Vector3f(mouseLoc.x, mouseLoc.y, 1); + dir.subtractLocal(pos).normalizeLocal(); + ray.setOrigin(pos); + ray.setDirection(dir); + node.collideWith(ray, results); + return results; + } +} diff --git a/JmeTests/src/jme3test/input/combomoves/ComboMove.java b/JmeTests/src/jme3test/input/combomoves/ComboMove.java new file mode 100644 index 0000000..ee1a3c3 --- /dev/null +++ b/JmeTests/src/jme3test/input/combomoves/ComboMove.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.input.combomoves; + +import java.util.ArrayList; +import java.util.List; + +public class ComboMove { + + public static class ComboMoveState { + + private String[] pressedMappings; + private String[] unpressedMappings; + private float timeElapsed; + + public ComboMoveState(String[] pressedMappings, String[] unpressedMappings, float timeElapsed) { + this.pressedMappings = pressedMappings; + this.unpressedMappings = unpressedMappings; + this.timeElapsed = timeElapsed; + } + + public String[] getUnpressedMappings() { + return unpressedMappings; + } + + public String[] getPressedMappings() { + return pressedMappings; + } + + public float getTimeElapsed() { + return timeElapsed; + } + + } + + private String moveName; + private List states = new ArrayList(); + private boolean useFinalState = true; + private float priority = 1; + private float castTime = 0.8f; + + private transient String[] pressed, unpressed; + private transient float timeElapsed; + + public ComboMove(String moveName){ + this.moveName = moveName; + } + + public float getPriority() { + return priority; + } + + public void setPriority(float priority) { + this.priority = priority; + } + + public float getCastTime() { + return castTime; + } + + public void setCastTime(float castTime) { + this.castTime = castTime; + } + + public boolean useFinalState() { + return useFinalState; + } + + public void setUseFinalState(boolean useFinalState) { + this.useFinalState = useFinalState; + } + + public ComboMove press(String ... pressedMappings){ + this.pressed = pressedMappings; + return this; + } + + public ComboMove notPress(String ... unpressedMappings){ + this.unpressed = unpressedMappings; + return this; + } + + public ComboMove timeElapsed(float time){ + this.timeElapsed = time; + return this; + } + + public void done(){ + if (pressed == null) + pressed = new String[0]; + + if (unpressed == null) + unpressed = new String[0]; + + states.add(new ComboMoveState(pressed, unpressed, timeElapsed)); + pressed = null; + unpressed = null; + timeElapsed = -1; + } + + public ComboMoveState getState(int num){ + return states.get(num); + } + + public int getNumStates(){ + return states.size(); + } + + public String getMoveName() { + return moveName; + } + +} diff --git a/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java b/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java new file mode 100644 index 0000000..9b8e266 --- /dev/null +++ b/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.input.combomoves; + +import java.util.Arrays; +import java.util.HashSet; +import jme3test.input.combomoves.ComboMove.ComboMoveState; + +public class ComboMoveExecution { + + private static final float TIME_LIMIT = 0.3f; + + private ComboMove moveDef; + private int state; + private float moveTime; + private boolean finalState = false; + + private String debugString = ""; // for debug only + + public ComboMoveExecution(ComboMove move){ + moveDef = move; + } + + private boolean isStateSatisfied(HashSet pressedMappings, float time, + ComboMoveState state){ + + if (state.getTimeElapsed() != -1f){ + // check if an appropriate amount of time has passed + // if the state requires it + if (moveTime + state.getTimeElapsed() >= time){ + return false; + } + } + for (String mapping : state.getPressedMappings()){ + if (!pressedMappings.contains(mapping)) + return false; + } + for (String mapping : state.getUnpressedMappings()){ + if (pressedMappings.contains(mapping)) + return false; + } + return true; + } + + public String getDebugString(){ + return debugString; + } + + public void updateExpiration(float time){ + if (!finalState && moveTime > 0 && moveTime + TIME_LIMIT < time){ + state = 0; + moveTime = 0; + finalState = false; + + // reset debug string. + debugString = ""; + } + } + + /** + * Check if move needs to be executed. + * @param pressedMappings Which mappings are currently pressed + * @param time Current time since start of app + * @return True if move needs to be executed. + */ + public boolean updateState(HashSet pressedMappings, float time){ + ComboMoveState currentState = moveDef.getState(state); + if (isStateSatisfied(pressedMappings, time, currentState)){ + state ++; + moveTime = time; + + if (state >= moveDef.getNumStates()){ + finalState = false; + state = 0; + + moveTime = time+0.5f; // this is for the reset of the debug string only. + debugString += ", -CASTING " + moveDef.getMoveName().toUpperCase() + "-"; + return true; + } + + // the following for debug only. + if (currentState.getPressedMappings().length > 0){ + if (!debugString.equals("")) + debugString += ", "; + + debugString += Arrays.toString(currentState.getPressedMappings()).replace(", ", "+"); + } + + if (moveDef.useFinalState() && state == moveDef.getNumStates() - 1){ + finalState = true; + } + } + return false; + } + +} diff --git a/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java b/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java new file mode 100644 index 0000000..3ca46db --- /dev/null +++ b/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.input.combomoves; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.ColorRGBA; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class TestComboMoves extends SimpleApplication implements ActionListener { + + private HashSet pressedMappings = new HashSet(); + + private ComboMove fireball; + private ComboMoveExecution fireballExec; + private BitmapText fireballText; + + private ComboMove shuriken; + private ComboMoveExecution shurikenExec; + private BitmapText shurikenText; + + private ComboMove jab; + private ComboMoveExecution jabExec; + private BitmapText jabText; + + private ComboMove punch; + private ComboMoveExecution punchExec; + private BitmapText punchText; + + private ComboMove currentMove = null; + private float currentMoveCastTime = 0; + private float time = 0; + + public static void main(String[] args){ + TestComboMoves app = new TestComboMoves(); + app.start(); + } + + @Override + public void simpleInitApp() { + setDisplayFps(false); + setDisplayStatView(false); + + // Create debug text + BitmapText helpText = new BitmapText(guiFont); + helpText.setLocalTranslation(0, settings.getHeight(), 0); + helpText.setText("Moves:\n" + + "Fireball: Down, Down+Right, Right\n"+ + "Shuriken: Left, Down, Attack1(Z)\n"+ + "Jab: Attack1(Z)\n"+ + "Punch: Attack1(Z), Attack1(Z)\n"); + guiNode.attachChild(helpText); + + fireballText = new BitmapText(guiFont); + fireballText.setColor(ColorRGBA.Orange); + fireballText.setLocalTranslation(0, fireballText.getLineHeight(), 0); + guiNode.attachChild(fireballText); + + shurikenText = new BitmapText(guiFont); + shurikenText.setColor(ColorRGBA.Cyan); + shurikenText.setLocalTranslation(0, shurikenText.getLineHeight()*2f, 0); + guiNode.attachChild(shurikenText); + + jabText = new BitmapText(guiFont); + jabText.setColor(ColorRGBA.Red); + jabText.setLocalTranslation(0, jabText.getLineHeight()*3f, 0); + guiNode.attachChild(jabText); + + punchText = new BitmapText(guiFont); + punchText.setColor(ColorRGBA.Green); + punchText.setLocalTranslation(0, punchText.getLineHeight()*4f, 0); + guiNode.attachChild(punchText); + + inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("Attack1", new KeyTrigger(KeyInput.KEY_Z)); + inputManager.addListener(this, "Left", "Right", "Up", "Down", "Attack1"); + + fireball = new ComboMove("Fireball"); + fireball.press("Down").notPress("Right").done(); + fireball.press("Right", "Down").done(); + fireball.press("Right").notPress("Down").done(); + fireball.notPress("Right", "Down").done(); + fireball.setUseFinalState(false); // no waiting on final state + + shuriken = new ComboMove("Shuriken"); + shuriken.press("Left").notPress("Down", "Attack1").done(); + shuriken.press("Down").notPress("Attack1").timeElapsed(0.11f).done(); + shuriken.press("Attack1").notPress("Left").timeElapsed(0.11f).done(); + shuriken.notPress("Left", "Down", "Attack1").done(); + + jab = new ComboMove("Jab"); + jab.setPriority(0.5f); // make jab less important than other moves + jab.press("Attack1").done(); + + punch = new ComboMove("Punch"); + punch.press("Attack1").done(); + punch.notPress("Attack1").done(); + punch.press("Attack1").done(); + + fireballExec = new ComboMoveExecution(fireball); + shurikenExec = new ComboMoveExecution(shuriken); + jabExec = new ComboMoveExecution(jab); + punchExec = new ComboMoveExecution(punch); + } + + @Override + public void simpleUpdate(float tpf){ + time += tpf; + + // check every frame if any executions are expired + shurikenExec.updateExpiration(time); + shurikenText.setText("Shuriken Exec: " + shurikenExec.getDebugString()); + + fireballExec.updateExpiration(time); + fireballText.setText("Fireball Exec: " + fireballExec.getDebugString()); + + jabExec.updateExpiration(time); + jabText.setText("Jab Exec: " + jabExec.getDebugString()); + + punchExec.updateExpiration(time); + punchText.setText("Punch Exec: " + punchExec.getDebugString()); + + if (currentMove != null){ + currentMoveCastTime -= tpf; + if (currentMoveCastTime <= 0){ + System.out.println("DONE CASTING " + currentMove.getMoveName()); + currentMoveCastTime = 0; + currentMove = null; + } + } + } + + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed){ + pressedMappings.add(name); + }else{ + pressedMappings.remove(name); + } + + // the pressed mappings was changed. update combo executions + List invokedMoves = new ArrayList(); + if (shurikenExec.updateState(pressedMappings, time)){ + invokedMoves.add(shuriken); + } + + if (fireballExec.updateState(pressedMappings, time)){ + invokedMoves.add(fireball); + } + + if (jabExec.updateState(pressedMappings, time)){ + invokedMoves.add(jab); + } + + if (punchExec.updateState(pressedMappings, time)){ + invokedMoves.add(punch); + } + + if (invokedMoves.size() > 0){ + // choose move with highest priority + float priority = 0; + ComboMove toExec = null; + for (ComboMove move : invokedMoves){ + if (move.getPriority() > priority){ + priority = move.getPriority(); + toExec = move; + } + } + if (currentMove != null && currentMove.getPriority() > toExec.getPriority()){ + return; + } + + currentMove = toExec; + currentMoveCastTime = currentMove.getCastTime(); + //System.out.println("CASTING " + currentMove.getMoveName()); + } + } + +} diff --git a/JmeTests/src/jme3test/light/ShadowTestUIManager.java b/JmeTests/src/jme3test/light/ShadowTestUIManager.java new file mode 100644 index 0000000..38d0548 --- /dev/null +++ b/JmeTests/src/jme3test/light/ShadowTestUIManager.java @@ -0,0 +1,154 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jme3test.light; + +import com.jme3.asset.AssetManager; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Node; +import com.jme3.shadow.AbstractShadowFilter; +import com.jme3.shadow.AbstractShadowRenderer; +import com.jme3.shadow.CompareMode; +import com.jme3.shadow.EdgeFilteringMode; + +/** + * + * @author Nehon + */ +public class ShadowTestUIManager implements ActionListener { + + private BitmapText shadowTypeText; + private BitmapText shadowCompareText; + private BitmapText shadowFilterText; + private BitmapText shadowIntensityText; + private final static String TYPE_TEXT = "(Space) Shadow type : "; + private final static String COMPARE_TEXT = "(enter) Shadow compare "; + private final static String FILTERING_TEXT = "(f) Edge filtering : "; + private final static String INTENSITY_TEXT = "(t:up, g:down) Shadow intensity : "; + private boolean hardwareShadows = true; + private AbstractShadowRenderer plsr; + private AbstractShadowFilter plsf; + private ViewPort viewPort; + private int filteringIndex = 0; + private int renderModeIndex = 0; + + + public ShadowTestUIManager(AssetManager assetManager,AbstractShadowRenderer plsr, AbstractShadowFilter plsf, + Node guiNode, InputManager inputManager, ViewPort viewPort) { + this.plsr = plsr; + this.plsf = plsf; + this.viewPort = viewPort; + BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + shadowTypeText = createText(guiFont); + shadowCompareText = createText(guiFont); + shadowFilterText = createText(guiFont); + shadowIntensityText = createText(guiFont); + + shadowTypeText.setText(TYPE_TEXT + "Processor"); + shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software")); + shadowFilterText.setText(FILTERING_TEXT + plsr.getEdgeFilteringMode().toString()); + shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); + + shadowTypeText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 20, 0); + shadowCompareText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 40, 0); + shadowFilterText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 60, 0); + shadowIntensityText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 80, 0); + + guiNode.attachChild(shadowTypeText); + guiNode.attachChild(shadowCompareText); + guiNode.attachChild(shadowFilterText); + guiNode.attachChild(shadowIntensityText); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("changeFiltering", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("ShadowUp", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addMapping("ShadowDown", new KeyTrigger(KeyInput.KEY_G)); + inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("toggleHW", new KeyTrigger(KeyInput.KEY_RETURN)); + + + inputManager.addListener(this, "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown", "changeFiltering"); + + } + + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + renderModeIndex += 1; + renderModeIndex %= 3; + + switch (renderModeIndex) { + case 0: + viewPort.addProcessor(plsr); + shadowTypeText.setText(TYPE_TEXT + "Processor"); + break; + case 1: + viewPort.removeProcessor(plsr); + plsf.setEnabled(true); + shadowTypeText.setText(TYPE_TEXT + "Filter"); + break; + case 2: + plsf.setEnabled(false); + shadowTypeText.setText(TYPE_TEXT + "None"); + break; + } + + + + } else if (name.equals("toggleHW") && keyPressed) { + hardwareShadows = !hardwareShadows; + plsr.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software); + plsf.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software); + + shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software")); + } + + + if (name.equals("changeFiltering") && keyPressed) { + filteringIndex = plsr.getEdgeFilteringMode().ordinal(); + filteringIndex = (filteringIndex + 1) % EdgeFilteringMode.values().length; + EdgeFilteringMode m = EdgeFilteringMode.values()[filteringIndex]; + plsr.setEdgeFilteringMode(m); + plsf.setEdgeFilteringMode(m); + shadowFilterText.setText(FILTERING_TEXT + m.toString()); + } + + if (name.equals("ShadowUp") && keyPressed) { + plsr.setShadowIntensity(plsr.getShadowIntensity() + 0.1f); + plsf.setShadowIntensity(plsf.getShadowIntensity() + 0.1f); + + shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); + } + if (name.equals("ShadowDown") && keyPressed) { + plsr.setShadowIntensity(plsr.getShadowIntensity() - 0.1f); + plsf.setShadowIntensity(plsf.getShadowIntensity() - 0.1f); + shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); + } + if (name.equals("ThicknessUp") && keyPressed) { + plsr.setEdgesThickness(plsr.getEdgesThickness() + 1); + plsf.setEdgesThickness(plsf.getEdgesThickness() + 1); + System.out.println("Shadow thickness : " + plsr.getEdgesThickness()); + } + if (name.equals("ThicknessDown") && keyPressed) { + plsr.setEdgesThickness(plsr.getEdgesThickness() - 1); + plsf.setEdgesThickness(plsf.getEdgesThickness() - 1); + System.out.println("Shadow thickness : " + plsr.getEdgesThickness()); + } + + } + + private BitmapText createText(BitmapFont guiFont) { + BitmapText t = new BitmapText(guiFont, false); + t.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f); + return t; + } +} diff --git a/JmeTests/src/jme3test/light/TestColorApp.java b/JmeTests/src/jme3test/light/TestColorApp.java new file mode 100644 index 0000000..03bef02 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestColorApp.java @@ -0,0 +1,90 @@ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.light.DirectionalLight; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.DirectionalLightShadowRenderer; + +public class TestColorApp extends SimpleApplication { + public static void main(String[] args) { + TestColorApp app = new TestColorApp(); + app.start(); + } + + @Override + public void simpleInitApp() { + // Lights + DirectionalLight sun = new DirectionalLight(); + Vector3f sunPosition = new Vector3f(1, -1, 1); + sun.setDirection(sunPosition); + sun.setColor(new ColorRGBA(1f,1f,1f,1f)); + rootNode.addLight(sun); + + //DirectionalLightShadowFilter sun_renderer = new DirectionalLightShadowFilter(assetManager, 2048, 4); + DirectionalLightShadowRenderer sun_renderer = new DirectionalLightShadowRenderer(assetManager, 2048, 1); + sun_renderer.setLight(sun); + viewPort.addProcessor(sun_renderer); + +// FilterPostProcessor fpp = new FilterPostProcessor(assetManager); +// fpp.addFilter(sun_renderer); +// viewPort.addProcessor(fpp); + + rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + + // Camera + viewPort.setBackgroundColor(new ColorRGBA(.6f, .6f, .6f, 1f)); + ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); + + + // Objects + // Ground Object + final Geometry groundBoxWhite = new Geometry("Box", new Box(7.5f, 7.5f, .25f)); + float[] f = {-FastMath.PI / 2, 3 * FastMath.PI / 2, 0f}; + groundBoxWhite.setLocalRotation(new Quaternion(f)); + groundBoxWhite.move(7.5f, -.75f, 7.5f); + final Material groundMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + groundMaterial.setColor("Diffuse", new ColorRGBA(.9f, .9f, .9f, .9f)); + groundBoxWhite.setMaterial(groundMaterial); + groundBoxWhite.addControl(chaseCam); + rootNode.attachChild(groundBoxWhite); + + // Planter + Geometry planterBox = new Geometry("Box", new Box(.5f, .5f, .5f)); + final Material planterMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + planterMaterial.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); + planterBox.setMaterial(groundMaterial); + planterBox.setLocalTranslation(10, 0, 9); + rootNode.attachChild(planterBox); + + // Action! + inputManager.addMapping("on", new KeyTrigger(KeyInput.KEY_Z)); + inputManager.addMapping("off", new KeyTrigger(KeyInput.KEY_X)); + + inputManager.addListener(new AnalogListener() { + @Override + public void onAnalog(String s, float v, float v1) { + if (s.equals("on")) { + groundBoxWhite.setMaterial(planterMaterial); + } + if (s.equals("off")) { + groundBoxWhite.setMaterial(groundMaterial); + } + } + }, "on", "off"); + + inputEnabled = true; + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestConeVSFrustum.java b/JmeTests/src/jme3test/light/TestConeVSFrustum.java new file mode 100644 index 0000000..d96edf7 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestConeVSFrustum.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseAxisTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.Camera; +import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Grid; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Cylinder; +import com.jme3.shadow.ShadowUtil; +import com.jme3.texture.Texture; +import com.jme3.util.TempVars; + +public class TestConeVSFrustum extends SimpleApplication { + + public static void main(String[] args) { + TestConeVSFrustum app = new TestConeVSFrustum(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + frustumCam = cam.clone(); + frustumCam.setFrustumFar(25); + Vector3f[] points = new Vector3f[8]; + for (int i = 0; i < 8; i++) { + points[i] = new Vector3f(); + } + ShadowUtil.updateFrustumPoints2(frustumCam, points); + WireFrustum frustumShape = new WireFrustum(points); + Geometry frustum = new Geometry("frustum", frustumShape); + frustum.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); + rootNode.attachChild(frustum); + + rootNode.addLight(new DirectionalLight()); + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.2f)); + rootNode.addLight(al); + + Grid grid = new Grid(50, 50, 5); + Geometry gridGeom = new Geometry("grid", grid); + gridGeom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); + gridGeom.getMaterial().setColor("Color", ColorRGBA.Gray); + rootNode.attachChild(gridGeom); + gridGeom.setLocalTranslation(-125, -25, -125); + +// flyCam.setMoveSpeed(30); +// flyCam.setDragToRotate(true); +// cam.setLocation(new Vector3f(56.182674f, 19.037334f, 7.093905f)); +// cam.setRotation(new Quaternion(0.0816657f, -0.82228005f, 0.12213967f, 0.5497892f)); + spotLight = new SpotLight(); + spotLight.setSpotRange(25); + spotLight.setSpotOuterAngle(10 * FastMath.DEG_TO_RAD); + + float radius = FastMath.tan(spotLight.getSpotOuterAngle()) * spotLight.getSpotRange(); + + Cylinder cylinder = new Cylinder(5, 16, 0.01f, radius, spotLight.getSpotRange(), true, false); + geom = new Geometry("light", cylinder); + geom.setMaterial(new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md")); + geom.getMaterial().setColor("Diffuse", ColorRGBA.White); + geom.getMaterial().setColor("Ambient", ColorRGBA.DarkGray); + geom.getMaterial().setBoolean("UseMaterialColors", true); + final LightNode ln = new LightNode("lb", spotLight); + ln.attachChild(geom); + geom.setLocalTranslation(0, -spotLight.getSpotRange() / 2f, 0); + geom.rotate(-FastMath.HALF_PI, 0, 0); + rootNode.attachChild(ln); +// ln.rotate(FastMath.QUARTER_PI, 0, 0); + // ln.setLocalTranslation(0, 0, -16); + + inputManager.addMapping("click", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + inputManager.addMapping("shift", new KeyTrigger(KeyInput.KEY_LSHIFT), new KeyTrigger(KeyInput.KEY_RSHIFT)); + inputManager.addMapping("middleClick", new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE)); + inputManager.addMapping("up", new MouseAxisTrigger(MouseInput.AXIS_Y, false)); + inputManager.addMapping("down", new MouseAxisTrigger(MouseInput.AXIS_Y, true)); + inputManager.addMapping("left", new MouseAxisTrigger(MouseInput.AXIS_X, true)); + inputManager.addMapping("right", new MouseAxisTrigger(MouseInput.AXIS_X, false)); + + + final Node camTarget = new Node("CamTarget"); + rootNode.attachChild(camTarget); + + ChaseCameraAppState chaser = new ChaseCameraAppState(); + chaser.setTarget(camTarget); + chaser.setMaxDistance(150); + chaser.setDefaultDistance(70); + chaser.setDefaultHorizontalRotation(FastMath.HALF_PI); + chaser.setMinVerticalRotation(-FastMath.PI); + chaser.setMaxVerticalRotation(FastMath.PI * 2); + chaser.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + stateManager.attach(chaser); + flyCam.setEnabled(false); + + inputManager.addListener(new AnalogListener() { + public void onAnalog(String name, float value, float tpf) { + Spatial s = null; + float mult = 1; + if (moving) { + s = ln; + } + if (panning) { + s = camTarget; + mult = -1; + } + if ((moving || panning) && s!=null) { + if (shift) { + if (name.equals("left")) { + tmp.set(cam.getDirection()); + s.rotate(tmpQuat.fromAngleAxis(value, tmp)); + } + if (name.equals("right")) { + tmp.set(cam.getDirection()); + s.rotate(tmpQuat.fromAngleAxis(-value, tmp)); + } + } else { + value *= MOVE_SPEED * mult; + if (name.equals("up")) { + tmp.set(cam.getUp()).multLocal(value); + s.move(tmp); + } + if (name.equals("down")) { + tmp.set(cam.getUp()).multLocal(-value); + s.move(tmp); + } + if (name.equals("left")) { + tmp.set(cam.getLeft()).multLocal(value); + s.move(tmp); + } + if (name.equals("right")) { + tmp.set(cam.getLeft()).multLocal(-value); + s.move(tmp); + } + } + } + } + }, "up", "down", "left", "right"); + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("click")) { + if (isPressed) { + moving = true; + } else { + moving = false; + } + } + if (name.equals("middleClick")) { + if (isPressed) { + panning = true; + } else { + panning = false; + } + } + if (name.equals("shift")) { + if (isPressed) { + shift = true; + } else { + shift = false; + } + } + } + }, "click", "middleClick", "shift"); + /** + * An unshaded textured cube. // * Uses texture from jme3-test-data + * library! + */ + Box boxMesh = new Box(1f, 1f, 1f); + boxGeo = new Geometry("A Textured Box", boxMesh); + Material boxMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Texture monkeyTex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + boxMat.setTexture("ColorMap", monkeyTex); + boxGeo.setMaterial(boxMat); +// rootNode.attachChild(boxGeo); +// +//boxGeo2 = boxGeo.clone(); +//rootNode.attachChild(boxGeo2); + System.err.println("light " + spotLight.getPosition()); + + } + Geometry boxGeo, boxGeo2; + private final static float MOVE_SPEED = 60; + Vector3f tmp = new Vector3f(); + Quaternion tmpQuat = new Quaternion(); + boolean moving, shift; + boolean panning; + Geometry geom; + SpotLight spotLight; + Camera frustumCam; + + @Override + public void simpleUpdate(float tpf) { + TempVars vars = TempVars.get(); + boolean intersect = spotLight.intersectsFrustum(frustumCam, vars); + + + if (intersect) { + geom.getMaterial().setColor("Diffuse", ColorRGBA.Green); + } else { + geom.getMaterial().setColor("Diffuse", ColorRGBA.White); + } + Vector3f farPoint = vars.vect1.set(spotLight.getPosition()).addLocal(vars.vect2.set(spotLight.getDirection()).multLocal(spotLight.getSpotRange())); + + //computing the radius of the base disc + float farRadius = (spotLight.getSpotRange() / FastMath.cos(spotLight.getSpotOuterAngle())) * FastMath.sin(spotLight.getSpotOuterAngle()); + //computing the projection direction : perpendicular to the light direction and coplanar with the direction vector and the normal vector + Vector3f perpDirection = vars.vect2.set(spotLight.getDirection()).crossLocal(frustumCam.getWorldPlane(3).getNormal()).normalizeLocal().crossLocal(spotLight.getDirection()); + //projecting the far point on the base disc perimeter + Vector3f projectedPoint = vars.vect3.set(farPoint).addLocal(perpDirection.multLocal(farRadius)); + + + vars.release(); +// boxGeo.setLocalTranslation(spotLight.getPosition()); + // boxGeo.setLocalTranslation(projectedPoint); + } +} diff --git a/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java b/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java new file mode 100644 index 0000000..79aacc6 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import com.jme3.util.TangentBinormalGenerator; + +public class TestDirectionalLightShadow extends SimpleApplication implements ActionListener, AnalogListener { + + public static final int SHADOWMAP_SIZE = 1024; + private Spatial[] obj; + private Material[] mat; + private DirectionalLightShadowRenderer dlsr; + private DirectionalLightShadowFilter dlsf; + private Geometry ground; + private Material matGroundU; + private Material matGroundL; + private AmbientLight al; + + public static void main(String[] args) { + TestDirectionalLightShadow app = new TestDirectionalLightShadow(); + app.start(); + } + private float frustumSize = 100; + + public void onAnalog(String name, float value, float tpf) { + if (cam.isParallelProjection()) { + // Instead of moving closer/farther to object, we zoom in/out. + if (name.equals("Size-")) { + frustumSize += 5f * tpf; + } else { + frustumSize -= 5f * tpf; + } + + float aspect = (float) cam.getWidth() / cam.getHeight(); + cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize); + } + } + + public void loadScene() { + obj = new Spatial[2]; + // Setup first view + + + mat = new Material[2]; + mat[0] = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + mat[1].setBoolean("UseMaterialColors", true); + mat[1].setColor("Ambient", ColorRGBA.White); + mat[1].setColor("Diffuse", ColorRGBA.White.clone()); + + + obj[0] = new Geometry("sphere", new Sphere(30, 30, 2)); + obj[0].setShadowMode(ShadowMode.CastAndReceive); + obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f)); + obj[1].setShadowMode(ShadowMode.CastAndReceive); + TangentBinormalGenerator.generate(obj[1]); + TangentBinormalGenerator.generate(obj[0]); + + Spatial t = obj[0].clone(false); + t.setLocalScale(10f); + t.setMaterial(mat[1]); + rootNode.attachChild(t); + t.setLocalTranslation(0, 25, 0); + + for (int i = 0; i < 60; i++) { + t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false); + t.setLocalScale(FastMath.nextRandomFloat() * 10f); + t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]); + rootNode.attachChild(t); + t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f)); + } + + Box b = new Box(1000, 2, 1000); + b.scaleTextureCoordinates(new Vector2f(10, 10)); + ground = new Geometry("soil", b); + ground.setLocalTranslation(0, 10, 550); + matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matGroundU.setColor("Color", ColorRGBA.Green); + + + matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matGroundL.setTexture("DiffuseMap", grass); + + ground.setMaterial(matGroundL); + + ground.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(ground); + + l = new DirectionalLight(); + //l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal()); + l.setDirection(new Vector3f(-1, -1, -1)); + rootNode.addLight(l); + + + al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.02f)); + rootNode.addLight(al); + + Spatial sky = SkyFactory.createSky(assetManager, + "Scenes/Beach/FullskiesSunset0068.dds", EnvMapType.CubeMap); + sky.setLocalScale(350); + + rootNode.attachChild(sky); + } + DirectionalLight l; + + @Override + public void simpleInitApp() { + // put the camera in a bad position +// cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f)); +// cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f)); + + cam.setLocation(new Vector3f(3.3720117f, 42.838284f, -83.43792f)); + cam.setRotation(new Quaternion(0.13833192f, -0.08969371f, 0.012581267f, 0.9862358f)); + + flyCam.setMoveSpeed(100); + + loadScene(); + + dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3); + dlsr.setLight(l); + dlsr.setLambda(0.55f); + dlsr.setShadowIntensity(0.8f); + dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + dlsr.displayDebug(); + viewPort.addProcessor(dlsr); + + dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3); + dlsf.setLight(l); + dlsf.setLambda(0.55f); + dlsf.setShadowIntensity(0.8f); + dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + dlsf.setEnabled(false); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(dlsf); + + viewPort.addProcessor(fpp); + + initInputs(); + } + + private void initInputs() { + + inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("lambdaUp", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M)); + inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_X)); + inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B)); + inputManager.addMapping("distance", new KeyTrigger(KeyInput.KEY_N)); + + + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_NUMPAD8)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_NUMPAD2)); + inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_NUMPAD6)); + inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_NUMPAD4)); + inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP)); + inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN)); + inputManager.addMapping("pp", new KeyTrigger(KeyInput.KEY_P)); + inputManager.addMapping("backShadows", new KeyTrigger(KeyInput.KEY_K)); + + + inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown", + "switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance", "ShadowUp", "ShadowDown", "backShadows"); + + ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort); + + inputManager.addListener(this, "Size+", "Size-"); + inputManager.addMapping("Size+", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Size-", new KeyTrigger(KeyInput.KEY_S)); + + shadowStabilizationText = new BitmapText(guiFont, false); + shadowStabilizationText.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f); + shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization()); + shadowStabilizationText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 100, 0); + guiNode.attachChild(shadowStabilizationText); + + + shadowZfarText = new BitmapText(guiFont, false); + shadowZfarText.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f); + shadowZfarText.setText("(n:on/off) Shadow extend to 500 and fade to 50 : " + (dlsr.getShadowZExtend() > 0)); + shadowZfarText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 120, 0); + guiNode.attachChild(shadowZfarText); + } + private BitmapText shadowStabilizationText; + private BitmapText shadowZfarText; + + public void onAction(String name, boolean keyPressed, float tpf) { + + + if (name.equals("pp") && keyPressed) { + if (cam.isParallelProjection()) { + cam.setFrustumPerspective(45, (float) cam.getWidth() / cam.getHeight(), 1, 1000); + } else { + cam.setParallelProjection(true); + float aspect = (float) cam.getWidth() / cam.getHeight(); + cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize); + + } + } + + if (name.equals("lambdaUp") && keyPressed) { + dlsr.setLambda(dlsr.getLambda() + 0.01f); + dlsf.setLambda(dlsr.getLambda() + 0.01f); + System.out.println("Lambda : " + dlsr.getLambda()); + } else if (name.equals("lambdaDown") && keyPressed) { + dlsr.setLambda(dlsr.getLambda() - 0.01f); + dlsf.setLambda(dlsr.getLambda() - 0.01f); + System.out.println("Lambda : " + dlsr.getLambda()); + } + if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && keyPressed) { + al.setColor(ColorRGBA.White.mult((1 - dlsr.getShadowIntensity()) * 0.2f)); + } + + if (name.equals("debug") && keyPressed) { + dlsr.displayFrustum(); + } + + if (name.equals("backShadows") && keyPressed) { + dlsr.setRenderBackFacesShadows(!dlsr.isRenderBackFacesShadows()); + dlsf.setRenderBackFacesShadows(!dlsf.isRenderBackFacesShadows()); + } + + if (name.equals("stabilize") && keyPressed) { + dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization()); + dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization()); + shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization()); + } + if (name.equals("distance") && keyPressed) { + if (dlsr.getShadowZExtend() > 0) { + dlsr.setShadowZExtend(0); + dlsr.setShadowZFadeLength(0); + dlsf.setShadowZExtend(0); + dlsf.setShadowZFadeLength(0); + + } else { + dlsr.setShadowZExtend(500); + dlsr.setShadowZFadeLength(50); + dlsf.setShadowZExtend(500); + dlsf.setShadowZFadeLength(50); + } + shadowZfarText.setText("(n:on/off) Shadow extend to 500 and fade to 50 : " + (dlsr.getShadowZExtend() > 0)); + + } + + if (name.equals("switchGroundMat") && keyPressed) { + if (ground.getMaterial() == matGroundL) { + ground.setMaterial(matGroundU); + } else { + ground.setMaterial(matGroundL); + } + } + + if (name.equals("up")) { + up = keyPressed; + } + if (name.equals("down")) { + down = keyPressed; + } + if (name.equals("right")) { + right = keyPressed; + } + if (name.equals("left")) { + left = keyPressed; + } + if (name.equals("fwd")) { + fwd = keyPressed; + } + if (name.equals("back")) { + back = keyPressed; + } + + } + boolean up = false; + boolean down = false; + boolean left = false; + boolean right = false; + boolean fwd = false; + boolean back = false; + float time = 0; + float s = 1f; + + @Override + public void simpleUpdate(float tpf) { + if (up) { + Vector3f v = l.getDirection(); + v.y += tpf / s; + setDir(v); + } + if (down) { + Vector3f v = l.getDirection(); + v.y -= tpf / s; + setDir(v); + } + if (right) { + Vector3f v = l.getDirection(); + v.x += tpf / s; + setDir(v); + } + if (left) { + Vector3f v = l.getDirection(); + v.x -= tpf / s; + setDir(v); + } + if (fwd) { + Vector3f v = l.getDirection(); + v.z += tpf / s; + setDir(v); + } + if (back) { + Vector3f v = l.getDirection(); + v.z -= tpf / s; + setDir(v); + } + + } + + private void setDir(Vector3f v) { + l.setDirection(v); + } +} diff --git a/JmeTests/src/jme3test/light/TestEnvironmentMapping.java b/JmeTests/src/jme3test/light/TestEnvironmentMapping.java new file mode 100644 index 0000000..4785b33 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestEnvironmentMapping.java @@ -0,0 +1,67 @@ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.input.ChaseCamera; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.texture.Texture; +import com.jme3.util.SkyFactory; + +/** + * test + * @author nehon + */ +public class TestEnvironmentMapping extends SimpleApplication { + + public static void main(String[] args) { + TestEnvironmentMapping app = new TestEnvironmentMapping(); + app.start(); + } + + @Override + public void simpleInitApp() { + final Node buggy = (Node) assetManager.loadModel("Models/Buggy/Buggy.j3o"); + + TextureKey key = new TextureKey("Textures/Sky/Bright/BrightSky.dds", true); + key.setGenerateMips(true); + key.setTextureTypeHint(Texture.Type.CubeMap); + final Texture tex = assetManager.loadTexture(key); + + for (Spatial geom : buggy.getChildren()) { + if (geom instanceof Geometry) { + Material m = ((Geometry) geom).getMaterial(); + m.setTexture("EnvMap", tex); + m.setVector3("FresnelParams", new Vector3f(0.05f, 0.18f, 0.11f)); + } + } + + flyCam.setEnabled(false); + + ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); + chaseCam.setLookAtOffset(new Vector3f(0,0.5f,-1.0f)); + buggy.addControl(chaseCam); + rootNode.attachChild(buggy); + rootNode.attachChild(SkyFactory.createSky(assetManager, tex, + SkyFactory.EnvMapType.CubeMap)); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + BloomFilter bf = new BloomFilter(BloomFilter.GlowMode.Objects); + bf.setBloomIntensity(2.3f); + bf.setExposurePower(0.6f); + + fpp.addFilter(bf); + + DirectionalLight l = new DirectionalLight(); + l.setDirection(new Vector3f(0, -1, -1)); + rootNode.addLight(l); + + viewPort.addProcessor(fpp); + } +} diff --git a/JmeTests/src/jme3test/light/TestLightNode.java b/JmeTests/src/jme3test/light/TestLightNode.java new file mode 100644 index 0000000..e2d337b --- /dev/null +++ b/JmeTests/src/jme3test/light/TestLightNode.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Torus; + +public class TestLightNode extends SimpleApplication { + + float angle; + Node movingNode; + + public static void main(String[] args){ + TestLightNode app = new TestLightNode(); + app.start(); + } + + @Override + public void simpleInitApp() { + Torus torus = new Torus(10, 6, 1, 3); +// Torus torus = new Torus(50, 30, 1, 3); + Geometry g = new Geometry("Torus Geom", torus); + g.rotate(-FastMath.HALF_PI, 0, 0); + g.center(); +// g.move(0, 1, 0); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 32f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Black); + mat.setColor("Diffuse", ColorRGBA.White); + mat.setColor("Specular", ColorRGBA.White); +// mat.setBoolean("VertexLighting", true); +// mat.setBoolean("LowQuality", true); + g.setMaterial(mat); + + rootNode.attachChild(g); + + Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + + movingNode=new Node("lightParentNode"); + movingNode.attachChild(lightMdl); + rootNode.attachChild(movingNode); + + PointLight pl = new PointLight(); + pl.setColor(ColorRGBA.Green); + pl.setRadius(4f); + rootNode.addLight(pl); + + LightNode lightNode=new LightNode("pointLight", pl); + movingNode.attachChild(lightNode); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.Red); + dl.setDirection(new Vector3f(0, 1, 0)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ +// cam.setLocation(new Vector3f(5.0347548f, 6.6481347f, 3.74853f)); +// cam.setRotation(new Quaternion(-0.19183293f, 0.80776674f, -0.37974006f, -0.40805697f)); + + angle += tpf; + angle %= FastMath.TWO_PI; + + movingNode.setLocalTranslation(new Vector3f(FastMath.cos(angle) * 3f, 2, FastMath.sin(angle) * 3f)); + } + +} diff --git a/JmeTests/src/jme3test/light/TestLightRadius.java b/JmeTests/src/jme3test/light/TestLightRadius.java new file mode 100644 index 0000000..f313309 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestLightRadius.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.jme3.scene.shape.Torus; + +public class TestLightRadius extends SimpleApplication { + + float pos, vel=1; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestLightRadius app = new TestLightRadius(); + app.start(); + } + + @Override + public void simpleInitApp() { + Torus torus = new Torus(10, 6, 1, 3); +// Torus torus = new Torus(50, 30, 1, 3); + Geometry g = new Geometry("Torus Geom", torus); + g.rotate(-FastMath.HALF_PI, 0, 0); + g.center(); +// g.move(0, 1, 0); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 32f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Black); + mat.setColor("Diffuse", ColorRGBA.White); + mat.setColor("Specular", ColorRGBA.White); +// mat.setBoolean("VertexLighting", true); +// mat.setBoolean("LowQuality", true); + g.setMaterial(mat); + + rootNode.attachChild(g); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.Green); + pl.setRadius(4f); + rootNode.addLight(pl); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.Red); + dl.setDirection(new Vector3f(0, 1, 0)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ +// cam.setLocation(new Vector3f(5.0347548f, 6.6481347f, 3.74853f)); +// cam.setRotation(new Quaternion(-0.19183293f, 0.80776674f, -0.37974006f, -0.40805697f)); + + pos += tpf * vel * 5f; + if (pos > 15){ + vel *= -1; + }else if (pos < -15){ + vel *= -1; + } + + pl.setPosition(new Vector3f(pos, 2, 0)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/light/TestManyLights.java b/JmeTests/src/jme3test/light/TestManyLights.java new file mode 100644 index 0000000..644344b --- /dev/null +++ b/JmeTests/src/jme3test/light/TestManyLights.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.scene.Node; + +public class TestManyLights extends SimpleApplication { + + public static void main(String[] args){ + TestManyLights app = new TestManyLights(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + + Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene"); + rootNode.attachChild(scene); +// guiNode.setCullHint(CullHint.Always); + } + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestManyLightsSingle.java b/JmeTests/src/jme3test/light/TestManyLightsSingle.java new file mode 100644 index 0000000..005634b --- /dev/null +++ b/JmeTests/src/jme3test/light/TestManyLightsSingle.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.BasicProfilerState; +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Box; +import com.jme3.util.MaterialDebugAppState; + +public class TestManyLightsSingle extends SimpleApplication { + + public static void main(String[] args) { + TestManyLightsSingle app = new TestManyLightsSingle(); + app.start(); + } + + /** + * Switch mode with space bar at run time + */ + TechniqueDef.LightMode lm = TechniqueDef.LightMode.SinglePass; + + @Override + public void simpleInitApp() { + renderManager.setPreferredLightMode(lm); + renderManager.setSinglePassLightBatchSize(6); + + flyCam.setMoveSpeed(10); + + Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene"); + rootNode.attachChild(scene); + Node n = (Node) rootNode.getChild(0); + final LightList lightList = n.getWorldLightList(); + final Geometry g = (Geometry) n.getChild("Grid-geom-1"); + + g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + + /* A colored lit cube. Needs light source! */ + Box boxMesh = new Box(1f, 1f, 1f); + final Geometry boxGeo = new Geometry("Colored Box", boxMesh); + Material boxMat = g.getMaterial().clone(); + boxMat.clearParam("DiffuseMap"); + boxMat.setBoolean("UseMaterialColors", true); + boxMat.setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + boxMat.setColor("Diffuse", ColorRGBA.Blue); + boxGeo.setMaterial(boxMat); + + final Node cubeNodes = new Node(); + n.attachChild(cubeNodes); + int nb = 0; + for (Light light : lightList) { + nb++; + PointLight p = (PointLight) light; + if (nb > 60) { + n.removeLight(light); + } else { + + LightNode ln = new LightNode("l", light); + n.attachChild(ln); + ln.setLocalTranslation(p.getPosition()); + int rand = FastMath.nextRandomInt(0, 3); + switch (rand) { + case 0: + light.setColor(ColorRGBA.Red); + // ln.addControl(new MoveControl(5f)); + break; + case 1: + light.setColor(ColorRGBA.Yellow); + // ln.addControl(new MoveControl(5f)); + break; + case 2: + light.setColor(ColorRGBA.Green); + //ln.addControl(new MoveControl(-5f)); + break; + case 3: + light.setColor(ColorRGBA.Orange); + //ln.addControl(new MoveControl(-5f)); + break; + } + } + Geometry b = boxGeo.clone(false); + cubeNodes.attachChild(b); + b.setLocalTranslation(p.getPosition().x, 2, p.getPosition().z); + + } + + +// cam.setLocation(new Vector3f(3.1893547f, 17.977385f, 30.8378f)); +// cam.setRotation(new Quaternion(0.14317635f, 0.82302624f, -0.23777823f, 0.49557027f)); + + cam.setLocation(new Vector3f(-1.8901939f, 29.34097f, 73.07533f)); + cam.setRotation(new Quaternion(0.0021000702f, 0.971012f, -0.23886925f, 0.008527749f)); + + + BasicProfilerState profiler = new BasicProfilerState(true); + profiler.setGraphScale(1000f); + + // getStateManager().attach(profiler); +// guiNode.setCullHint(CullHint.Always); + + + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(50); + + final MaterialDebugAppState debug = new MaterialDebugAppState(); + stateManager.attach(debug); + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggle") && isPressed) { + if (lm == TechniqueDef.LightMode.SinglePass) { + lm = TechniqueDef.LightMode.MultiPass; + helloText.setText("(Multi pass)"); + } else { + lm = TechniqueDef.LightMode.SinglePass; + helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); + } + renderManager.setPreferredLightMode(lm); + reloadScene(g, boxGeo, cubeNodes); + } + if (name.equals("lightsUp") && isPressed) { + renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() + 1); + helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); + } + if (name.equals("lightsDown") && isPressed) { + renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() - 1); + helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); + } + if (name.equals("toggleOnOff") && isPressed) { + for (final Light light : lightList) { + if (light instanceof AmbientLight) { + continue; + } + + light.setEnabled(!light.isEnabled()); + } + } + } + }, "toggle", "lightsUp", "lightsDown", "toggleOnOff"); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("toggleOnOff", new KeyTrigger(KeyInput.KEY_L)); + + + SpotLight spot = new SpotLight(); + spot.setDirection(new Vector3f(-1f, -1f, -1f).normalizeLocal()); + spot.setColor(ColorRGBA.Blue.mult(5)); + spot.setSpotOuterAngle(FastMath.DEG_TO_RAD * 20); + spot.setSpotInnerAngle(FastMath.DEG_TO_RAD * 5); + spot.setPosition(new Vector3f(10, 10, 20)); + rootNode.addLight(spot); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, 1)); + rootNode.addLight(dl); + + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + rootNode.addLight(al); + + + /** + * Write text on the screen (HUD) + */ + guiNode.detachAllChildren(); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + helloText = new BitmapText(guiFont, false); + helloText.setSize(guiFont.getCharSet().getRenderedSize()); + helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); + helloText.setLocalTranslation(300, helloText.getLineHeight(), 0); + guiNode.attachChild(helloText); + } + + protected void reloadScene(Geometry g, Geometry boxGeo, Node cubeNodes) { + MaterialDebugAppState debug = stateManager.getState(MaterialDebugAppState.class); + Material m = debug.reloadMaterial(g.getMaterial()); + if (m != null) { + g.setMaterial(m); + } + m = debug.reloadMaterial(boxGeo.getMaterial()); + if (m != null) { + cubeNodes.setMaterial(m); + } + } + + BitmapText helloText; + long time; + long nbFrames; + long startTime = 0; + + @Override + public void simpleUpdate(float tpf) { +// if (nbFrames == 4000) { +// startTime = System.nanoTime(); +// } +// if (nbFrames > 4000) { +// time = System.nanoTime(); +// float average = ((float) time - (float) startTime) / ((float) nbFrames - 4000f); +// helloText.setText("Average = " + average); +// } +// nbFrames++; + } + + class MoveControl extends AbstractControl { + + float direction; + Vector3f origPos = new Vector3f(); + + public MoveControl(float direction) { + this.direction = direction; + } + + @Override + public void setSpatial(Spatial spatial) { + super.setSpatial(spatial); //To change body of generated methods, choose Tools | Templates. + origPos.set(spatial.getLocalTranslation()); + } + float time = 0; + + @Override + protected void controlUpdate(float tpf) { + time += tpf; + spatial.setLocalTranslation(origPos.x + FastMath.cos(time) * direction, origPos.y, origPos.z + FastMath.sin(time) * direction); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java b/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java new file mode 100644 index 0000000..473ba8d --- /dev/null +++ b/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.PointLightShadowFilter; +import com.jme3.shadow.PointLightShadowRenderer; +import com.jme3.shadow.SpotLightShadowFilter; +import com.jme3.shadow.SpotLightShadowRenderer; + +public class TestPointDirectionalAndSpotLightShadows extends SimpleApplication { + public static final int SHADOWMAP_SIZE = 512; + + public static void main(String[] args) { + TestPointDirectionalAndSpotLightShadows app = new TestPointDirectionalAndSpotLightShadows(); + app.start(); + } + Node lightNode; + PointLightShadowRenderer plsr; + PointLightShadowFilter plsf; + DirectionalLightShadowRenderer dlsr; + DirectionalLightShadowFilter dlsf; + SpotLightShadowRenderer slsr; + SpotLightShadowFilter slsf; + SpotLight spotLight; + + boolean useFilter = false; + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f)); + cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f)); + + + Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o"); + scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(scene); + rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive); + lightNode = (Node) rootNode.getChild("Lamp"); + Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.setShadowMode(RenderQueue.ShadowMode.Off); + lightNode.attachChild(lightMdl); + //lightMdl.setLocalTranslation(lightNode.getLocalTranslation()); + + + Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(box); + box.setLocalTranslation(-1f, 0.5f, -2); + + ((PointLight) scene.getLocalLightList().get(0)).setColor(ColorRGBA.Red); + + plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE); + plsr.setLight((PointLight) scene.getLocalLightList().get(0)); + plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + + + plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE); + plsf.setLight((PointLight) scene.getLocalLightList().get(0)); + plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + plsf.setEnabled(useFilter); + + //DIRECTIONAL LIGHT + DirectionalLight directionalLight = new DirectionalLight(); + rootNode.addLight(directionalLight); + directionalLight.setColor(ColorRGBA.Blue); + directionalLight.setDirection(new Vector3f(-1f, -.2f, 0f)); + dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE*2, 4); + dlsr.setLight(directionalLight); + dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE*2, 4); + dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + dlsf.setLight(directionalLight); + dlsf.setEnabled(useFilter); + + //SPOT LIGHT + spotLight = new SpotLight(); + spotLight.setDirection(new Vector3f(1f,-1f,0f)); + spotLight.setPosition(new Vector3f(-1f,3f,0f)); + spotLight.setSpotOuterAngle(0.5f); + spotLight.setColor(ColorRGBA.Green); + Sphere sphere = new Sphere(8, 8, .1f); + Geometry sphereGeometry = new Geometry("Sphere", sphere); + sphereGeometry.setLocalTranslation(-1f, 3f, 0f); + sphereGeometry.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m")); + rootNode.attachChild(sphereGeometry); + rootNode.addLight(spotLight); + + slsr = new SpotLightShadowRenderer(assetManager, SHADOWMAP_SIZE); + slsr.setLight(spotLight); + slsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + slsf = new SpotLightShadowFilter(assetManager, SHADOWMAP_SIZE); + slsf.setLight(spotLight); + slsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + slsf.setEnabled(useFilter); + + + + if (!useFilter)viewPort.addProcessor(slsr); + if (!useFilter)viewPort.addProcessor(plsr); + if (!useFilter)viewPort.addProcessor(dlsr); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(plsf); + fpp.addFilter(dlsf); + fpp.addFilter(slsf); + viewPort.addProcessor(fpp); + + ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManPls = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManDls = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManSls = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort); + + } + + float timeElapsed = 0.0f; + @Override + public void simpleUpdate(float tpf) { + timeElapsed += tpf; + lightNode.setLocalTranslation(FastMath.cos(timeElapsed), lightNode.getLocalTranslation().y, FastMath.sin(timeElapsed)); + spotLight.setDirection(new Vector3f(FastMath.cos(-timeElapsed*.7f), -1.0f, FastMath.sin(-timeElapsed*.7f))); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestPointLightShadows.java b/JmeTests/src/jme3test/light/TestPointLightShadows.java new file mode 100644 index 0000000..8007971 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestPointLightShadows.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.controls.ActionListener; +import com.jme3.light.AmbientLight; +import com.jme3.light.PointLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.PointLightShadowFilter; +import com.jme3.shadow.PointLightShadowRenderer; + +public class TestPointLightShadows extends SimpleApplication implements ActionListener{ + public static final int SHADOWMAP_SIZE = 512; + + public static void main(String[] args) { + TestPointLightShadows app = new TestPointLightShadows(); + app.start(); + } + Node lightNode; + PointLightShadowRenderer plsr; + PointLightShadowFilter plsf; + AmbientLight al; + + @Override + public void simpleInitApp () { + flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f)); + cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f)); + + al = new AmbientLight(ColorRGBA.White.mult(0.02f)); + rootNode.addLight(al); + + + + + Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o"); + scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(scene); + rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive); + lightNode = (Node) rootNode.getChild("Lamp"); + Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.setShadowMode(RenderQueue.ShadowMode.Off); + lightNode.attachChild(lightMdl); + //lightMdl.setLocalTranslation(lightNode.getLocalTranslation()); + + + Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(box); + box.setLocalTranslation(-1f, 0.5f, -2); + + + plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE); + plsr.setLight((PointLight) scene.getLocalLightList().get(0)); + plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + plsr.setShadowZExtend(15); + plsr.setShadowZFadeLength(5); + plsr.setShadowIntensity(0.9f); + // plsr.setFlushQueues(false); + //plsr.displayFrustum(); + plsr.displayDebug(); + viewPort.addProcessor(plsr); + + + plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE); + plsf.setLight((PointLight) scene.getLocalLightList().get(0)); + plsf.setShadowZExtend(15); + plsf.setShadowZFadeLength(5); + plsf.setShadowIntensity(0.8f); + plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + plsf.setEnabled(false); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(plsf); + viewPort.addProcessor(fpp); + inputManager.addListener(this,"ShadowUp","ShadowDown"); + ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); + + } + + @Override + public void simpleUpdate(float tpf) { + // lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && isPressed) { + al.setColor(ColorRGBA.White.mult((1 - plsr.getShadowIntensity()) * 0.2f)); + } + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestShadowBug.java b/JmeTests/src/jme3test/light/TestShadowBug.java new file mode 100644 index 0000000..acf2d6d --- /dev/null +++ b/JmeTests/src/jme3test/light/TestShadowBug.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.PointLightShadowRenderer; +import com.jme3.shadow.SpotLightShadowRenderer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + + +public class TestShadowBug extends SimpleApplication { + public static void main(String[] args) { + TestShadowBug app = new TestShadowBug(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(100f); + rootNode.attachChild(makeFloor()); + + Node characters = new Node("Characters"); + characters.setShadowMode(ShadowMode.Cast); + rootNode.attachChild(characters); + + Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + golem.scale(0.5f); + golem.setLocalTranslation(200.0f, -6f, 200f); + golem.setShadowMode(ShadowMode.CastAndReceive); + characters.attachChild(golem); + + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-1f, -1f, 1f)); + sun.setColor(ColorRGBA.White.mult(1.3f)); + rootNode.addLight(sun); + characters.addLight(sun); + + SpotLight spot = new SpotLight(); + spot.setSpotRange(13f); // distance + spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam) + spot.setSpotOuterAngle(20f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light) + spot.setColor(ColorRGBA.White.mult(1.3f)); // light color + spot.setPosition(new Vector3f(192.0f, -1f, 192f)); + spot.setDirection(new Vector3f(1, -0.5f, 1)); + rootNode.addLight(spot); + + PointLight lamp_light = new PointLight(); + lamp_light.setColor(ColorRGBA.Yellow); + lamp_light.setRadius(20f); + lamp_light.setPosition(new Vector3f(210.0f, 0f, 210f)); + rootNode.addLight(lamp_light); + + SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512); + slsr.setLight(spot); + slsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + slsr.setShadowIntensity(0.6f); + viewPort.addProcessor(slsr); + + PointLightShadowRenderer plsr = new PointLightShadowRenderer(assetManager, 512); + plsr.setLight(lamp_light); + plsr.setShadowIntensity(0.6f); + plsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + viewPort.addProcessor(plsr); + + viewPort.getCamera().setLocation(new Vector3f(192.0f, 10f, 192f)); + float[] angles = new float[]{3.14f/2, 3.14f/2, 0}; + viewPort.getCamera().setRotation(new Quaternion(angles)); + } + + protected Geometry makeFloor() { + Box box = new Box(220, .2f, 220); + box.scaleTextureCoordinates(new Vector2f(10, 10)); + Geometry floor = new Geometry("the Floor", box); + floor.setLocalTranslation(200, -9, 200); + Material matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matGroundL.setTexture("DiffuseMap", grass); + floor.setMaterial(matGroundL); + floor.setShadowMode(ShadowMode.CastAndReceive); + return floor; + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/light/TestShadowsPerf.java b/JmeTests/src/jme3test/light/TestShadowsPerf.java new file mode 100644 index 0000000..f267b1d --- /dev/null +++ b/JmeTests/src/jme3test/light/TestShadowsPerf.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.util.TangentBinormalGenerator; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestShadowsPerf extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args) { + TestShadowsPerf app = new TestShadowsPerf(); + app.start(); + } + Geometry sphere; + Material mat; + + @Override + public void simpleInitApp() { + Logger.getLogger("com.jme3").setLevel(Level.SEVERE); + flyCam.setMoveSpeed(50); + flyCam.setEnabled(false); + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + cam.setLocation(new Vector3f(-53.952988f, 27.15874f, -32.875023f)); + cam.setRotation(new Quaternion(0.1564309f, 0.6910534f, -0.15713608f, 0.6879555f)); + +// cam.setLocation(new Vector3f(53.64627f, 130.56f, -11.247704f)); +// cam.setRotation(new Quaternion(-6.5737107E-4f, 0.76819664f, -0.64021313f, -7.886125E-4f)); +//// + cam.setFrustumFar(500); + + mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + + Box b = new Box(800, 1, 700); + b.scaleTextureCoordinates(new Vector2f(50, 50)); + Geometry ground = new Geometry("ground", b); + ground.setMaterial(mat); + rootNode.attachChild(ground); + ground.setShadowMode(ShadowMode.Receive); + + Sphere sphMesh = new Sphere(32, 32, 1); + sphMesh.setTextureMode(Sphere.TextureMode.Projected); + sphMesh.updateGeometry(32, 32, 1, false, false); + TangentBinormalGenerator.generate(sphMesh); + + sphere = new Geometry("Rock Ball", sphMesh); + sphere.setLocalTranslation(0, 5, 0); + sphere.setMaterial(mat); + sphere.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(sphere); + + + + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(0, -1, 0).normalizeLocal()); + dl.setColor(ColorRGBA.White); + rootNode.addLight(dl); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.7f)); + rootNode.addLight(al); + //rootNode.setShadowMode(ShadowMode.CastAndReceive); + + createballs(); + + final DirectionalLightShadowRenderer pssmRenderer = new DirectionalLightShadowRenderer(assetManager, 1024, 4); + viewPort.addProcessor(pssmRenderer); +// +// final PssmShadowFilter pssmRenderer = new PssmShadowFilter(assetManager, 1024, 4); +// FilterPostProcessor fpp = new FilterPostProcessor(assetManager); +// fpp.addFilter(pssmRenderer); +// viewPort.addProcessor(fpp); + + pssmRenderer.setLight(dl); + pssmRenderer.setLambda(0.55f); + pssmRenderer.setShadowIntensity(0.55f); + pssmRenderer.setShadowCompareMode(com.jme3.shadow.CompareMode.Software); + pssmRenderer.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + //pssmRenderer.displayDebug(); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("display") && isPressed) { + //pssmRenderer.debugFrustrums(); + System.out.println("tetetetet"); + } + if (name.equals("add") && isPressed) { + createballs(); + } + } + }, "display", "add"); + inputManager.addMapping("display", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("add", new KeyTrigger(KeyInput.KEY_RETURN)); + } + int val = 0; + + private void createballs() { + System.out.println((frames / time) + ";" + val); + + + for (int i = val; i < val+1 ; i++) { + + Geometry s = sphere.clone().clone(false); + s.setMaterial(mat); + s.setLocalTranslation(i - 30, 5, (((i) * 2) % 40) - 50); + s.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(s); + } + if (val == 300) { + stop(); + } + val += 1; + time = 0; + frames = 0; + } + float time; + float frames = 0; + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + frames++; + if (time > 1) { + createballs(); + } + } +} diff --git a/JmeTests/src/jme3test/light/TestSimpleLighting.java b/JmeTests/src/jme3test/light/TestSimpleLighting.java new file mode 100644 index 0000000..840aa2f --- /dev/null +++ b/JmeTests/src/jme3test/light/TestSimpleLighting.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.MaterialDebugAppState; +import com.jme3.util.TangentBinormalGenerator; + +public class TestSimpleLighting extends SimpleApplication { + + float angle; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestSimpleLighting app = new TestSimpleLighting(); + app.start(); + } + + @Override + public void simpleInitApp() { + Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + TangentBinormalGenerator.generate(teapot.getMesh(), true); + + teapot.setLocalScale(2f); + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); +// mat.selectTechnique("GBuf"); + mat.setFloat("Shininess", 25); + mat.setBoolean("UseMaterialColors", true); + cam.setLocation(new Vector3f(0.015041917f, 0.4572918f, 5.2874837f)); + cam.setRotation(new Quaternion(-1.8875003E-4f, 0.99882424f, 0.04832061f, 0.0039016632f)); + +// mat.setTexture("ColorRamp", assetManager.loadTexture("Textures/ColorRamp/cloudy.png")); +// +// mat.setBoolean("VTangent", true); +// mat.setBoolean("Minnaert", true); +// mat.setBoolean("WardIso", true); +// mat.setBoolean("VertexLighting", true); +// mat.setBoolean("LowQuality", true); +// mat.setBoolean("HighQuality", true); + + mat.setColor("Ambient", ColorRGBA.Black); + mat.setColor("Diffuse", ColorRGBA.Gray); + mat.setColor("Specular", ColorRGBA.Gray); + + teapot.setMaterial(mat); + rootNode.attachChild(teapot); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.getMesh().setStatic(); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setRadius(4f); + rootNode.addLight(pl); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + dl.setColor(ColorRGBA.Green); + rootNode.addLight(dl); + + + MaterialDebugAppState debug = new MaterialDebugAppState(); + debug.registerBinding("Common/ShaderLib/BlinnPhongLighting.glsllib", teapot); + stateManager.attach(debug); + setPauseOnLostFocus(false); + flyCam.setDragToRotate(true); + + } + + @Override + public void simpleUpdate(float tpf){ +// cam.setLocation(new Vector3f(2.0632997f, 1.9493936f, 2.6885238f)); +// cam.setRotation(new Quaternion(-0.053555284f, 0.9407851f, -0.17754152f, -0.28378546f)); + + angle += tpf; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 0.5f, FastMath.sin(angle) * 2f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/light/TestSpotLight.java b/JmeTests/src/jme3test/light/TestSpotLight.java new file mode 100644 index 0000000..0cd4512 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestSpotLight.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.TangentBinormalGenerator; + +public class TestSpotLight extends SimpleApplication { + + private Vector3f lightTarget = new Vector3f(12, 3.5f, 30); + + public static void main(String[] args){ + TestSpotLight app = new TestSpotLight(); + app.start(); + } + + SpotLight spot; + Geometry lightMdl; + public void setupLighting(){ + AmbientLight al=new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.02f)); + rootNode.addLight(al); + + spot=new SpotLight(); + + spot.setSpotRange(1000); + spot.setSpotInnerAngle(5*FastMath.DEG_TO_RAD); + spot.setSpotOuterAngle(10*FastMath.DEG_TO_RAD); + spot.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f)); + spot.setDirection(lightTarget.subtract(spot.getPosition())); + spot.setColor(ColorRGBA.White.mult(2)); + rootNode.addLight(spot); + + +// PointLight pl=new PointLight(); +// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f)); +// pl.setRadius(1000); +// pl.setColor(ColorRGBA.White.mult(2)); +// rootNode.addLight(pl); + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f)); + lightMdl.setLocalScale(5); + rootNode.attachChild(lightMdl); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f))); +// dl.setColor(ColorRGBA.White.mult(2)); +// rootNode.addLight(dl); + + + } + + public void setupFloor(){ + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); + mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); + // mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat); + mat.setFloat("Shininess",3); + // mat.setBoolean("VertexLighting", true); + + + Box floor = new Box(50, 1f, 50); + TangentBinormalGenerator.generate(floor); + floor.scaleTextureCoordinates(new Vector2f(5, 5)); + Geometry floorGeom = new Geometry("Floor", floor); + floorGeom.setMaterial(mat); + floorGeom.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(floorGeom); + } + + + + public void setupSignpost(){ + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + // mat.setBoolean("VertexLighting", true); + signpost.setMaterial(mat); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 3.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + TangentBinormalGenerator.generate(signpost); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f)); + cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f)); + flyCam.setMoveSpeed(30); + + setupLighting(); + setupFloor(); + setupSignpost(); + + + } + + float angle; + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + angle += tpf; + angle %= FastMath.TWO_PI; + + spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f)); + lightMdl.setLocalTranslation(spot.getPosition()); + spot.setDirection(lightTarget.subtract(spot.getPosition())); + } + + + +} diff --git a/JmeTests/src/jme3test/light/TestSpotLightShadows.java b/JmeTests/src/jme3test/light/TestSpotLightShadows.java new file mode 100644 index 0000000..52a5dc8 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestSpotLightShadows.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.SpotLightShadowFilter; +import com.jme3.shadow.SpotLightShadowRenderer; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.MaterialDebugAppState; +import com.jme3.util.TangentBinormalGenerator; + +public class TestSpotLightShadows extends SimpleApplication { + + private Vector3f lightTarget = new Vector3f(12, 3.5f, 30); + + public static void main(String[] args) { + TestSpotLightShadows app = new TestSpotLightShadows(); + app.start(); + } + SpotLight spot; + Geometry lightMdl; + + public void setupLighting() { + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.02f)); + rootNode.addLight(al); + + rootNode.setShadowMode(ShadowMode.CastAndReceive); + + spot = new SpotLight(); + + spot.setSpotRange(1000); + spot.setSpotInnerAngle(5f * FastMath.DEG_TO_RAD); + spot.setSpotOuterAngle(10 * FastMath.DEG_TO_RAD); + spot.setPosition(new Vector3f(70.70334f, 34.013165f, 27.1017f)); + spot.setDirection(lightTarget.subtract(spot.getPosition()).normalizeLocal()); + spot.setColor(ColorRGBA.White.mult(2)); + rootNode.addLight(spot); + + +// PointLight pl=new PointLight(); +// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f)); +// pl.setRadius(1000); +// pl.setColor(ColorRGBA.White.mult(2)); +// rootNode.addLight(pl); + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f)); + lightMdl.setLocalScale(5); + rootNode.attachChild(lightMdl); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f))); +// dl.setColor(ColorRGBA.White.mult(0.7f)); +// rootNode.addLight(dl); + + + final SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512); + slsr.setLight(spot); + slsr.setShadowIntensity(0.5f); + slsr.setShadowZExtend(100); + slsr.setShadowZFadeLength(5); + slsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); + viewPort.addProcessor(slsr); + + SpotLightShadowFilter slsf = new SpotLightShadowFilter(assetManager, 512); + slsf.setLight(spot); + slsf.setShadowIntensity(0.5f); + slsf.setShadowZExtend(100); + slsf.setShadowZFadeLength(5); + slsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); + slsf.setEnabled(false); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(slsf); + viewPort.addProcessor(fpp); + + ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort); + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("stop") && isPressed) { + stop = !stop; + // slsr.displayFrustum(); + System.out.println("pos : " + spot.getPosition()); + System.out.println("dir : " + spot.getDirection()); + } + } + }, "stop"); + + inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_1)); + flyCam.setDragToRotate(true); + } + + public void setupFloor() { + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); + mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Diffuse", ColorRGBA.White.clone()); + mat.setColor("Ambient", ColorRGBA.White.clone()); + // mat.setColor("Specular", ColorRGBA.White.clone()); + // mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat); + mat.setFloat("Shininess", 0); + // mat.setBoolean("VertexLighting", true); + + + Box floor = new Box(50, 1f, 50); + TangentBinormalGenerator.generate(floor); + floor.scaleTextureCoordinates(new Vector2f(5, 5)); + Geometry floorGeom = new Geometry("Floor", floor); + floorGeom.setMaterial(mat); + floorGeom.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(floorGeom); + } + + public void setupSignpost() { + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + // mat.setBoolean("VertexLighting", true); + signpost.setMaterial(mat); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 3.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + TangentBinormalGenerator.generate(signpost); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f)); + cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f)); + flyCam.setMoveSpeed(30); + + setupLighting(); + setupFloor(); + setupSignpost(); + + + } + float angle; + boolean stop = true; + + @Override + public void simpleUpdate(float tpf) { + if (!stop) { + super.simpleUpdate(tpf); + angle += tpf; + angle %= FastMath.TWO_PI; + + spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f)); + lightMdl.setLocalTranslation(spot.getPosition()); + spot.setDirection(lightTarget.subtract(spot.getPosition())); + } + } +} diff --git a/JmeTests/src/jme3test/light/TestSpotLightTerrain.java b/JmeTests/src/jme3test/light/TestSpotLightTerrain.java new file mode 100644 index 0000000..02bd48a --- /dev/null +++ b/JmeTests/src/jme3test/light/TestSpotLightTerrain.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.font.BitmapText; +import com.jme3.light.AmbientLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; + +/** + * Uses the terrain's lighting texture with normal maps and lights. + * + * @author bowens + */ +public class TestSpotLightTerrain extends SimpleApplication { + + private TerrainQuad terrain; + Material matTerrain; + Material matWire; + boolean wireframe = false; + boolean triPlanar = false; + boolean wardiso = false; + boolean minnaert = false; + protected BitmapText hintText; + PointLight pl; + Geometry lightMdl; + private float grassScale = 64; + private float dirtScale = 16; + private float rockScale = 128; + SpotLight sl; + + public static void main(String[] args) { + TestSpotLightTerrain app = new TestSpotLightTerrain(); + app.start(); + } + + + @Override + public void simpleInitApp() { + makeTerrain(); + flyCam.setMoveSpeed(50); + + sl = new SpotLight(); + sl.setSpotRange(100); + sl.setSpotOuterAngle(20 * FastMath.DEG_TO_RAD); + sl.setSpotInnerAngle(15 * FastMath.DEG_TO_RAD); + sl.setDirection(new Vector3f(-0.39820394f, -0.73094344f, 0.55421597f)); + sl.setPosition(new Vector3f(-64.61567f, -87.615425f, -202.41328f)); + rootNode.addLight(sl); + + AmbientLight ambLight = new AmbientLight(); + ambLight.setColor(ColorRGBA.Black); + rootNode.addLight(ambLight); + + cam.setLocation(new Vector3f(-41.219646f, 0.8363f, -171.67267f)); + cam.setRotation(new Quaternion(-0.04562731f, 0.89917684f, -0.09668826f, -0.4243236f)); + sl.setDirection(cam.getDirection()); + sl.setPosition(cam.getLocation()); + + } + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + sl.setDirection(cam.getDirection()); + sl.setPosition(cam.getLocation()); + + } + + private void makeTerrain() { + // TERRAIN TEXTURE material + matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matTerrain.setBoolean("useTriPlanarMapping", false); + matTerrain.setBoolean("WardIso", true); + + // ALPHA map (for splat textures) + matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png")); + matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png")); + + // HEIGHTMAP image (for the terrain heightmap) + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap", grass); + matTerrain.setFloat("DiffuseMap_0_scale", grassScale); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_1", dirt); + matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_2", rock); + matTerrain.setFloat("DiffuseMap_2_scale", rockScale); + + // BRICK texture + Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + brick.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_3", brick); + matTerrain.setFloat("DiffuseMap_3_scale", rockScale); + + // RIVER ROCK texture + Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); + riverRock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_4", riverRock); + matTerrain.setFloat("DiffuseMap_4_scale", rockScale); + + + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matTerrain.setTexture("NormalMap", normalMap0); + matTerrain.setTexture("NormalMap_1", normalMap2); + matTerrain.setTexture("NormalMap_2", normalMap2); + matTerrain.setTexture("NormalMap_4", normalMap2); + + // WIREFRAME material + matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWire.getAdditionalRenderState().setWireframe(true); + matWire.setColor("Color", ColorRGBA.Green); + + createSky(); + + // CREATE HEIGHTMAP + AbstractHeightMap heightmap = null; + try { + //heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3); + + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 1f); + heightmap.load(); + + } catch (Exception e) { + e.printStackTrace(); + } + + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations + TerrainLodControl control = new TerrainLodControl(terrain, getCamera()); + control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); + terrain.addControl(control); + terrain.setMaterial(matTerrain); + terrain.setModelBound(new BoundingBox()); + terrain.updateModelBound(); + terrain.setLocalTranslation(0, -100, 0); + terrain.setLocalScale(1f, 1f, 1f); + rootNode.attachChild(terrain); + } + + private void createSky() { + Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); + Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); + Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); + Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); + Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); + Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); + + Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); + rootNode.attachChild(sky); + } + + +} diff --git a/JmeTests/src/jme3test/light/TestTangentCube.java b/JmeTests/src/jme3test/light/TestTangentCube.java new file mode 100644 index 0000000..c7c3b67 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTangentCube.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.util.TangentBinormalGenerator; + +/** + * + * @author Nehon + */ +public class TestTangentCube extends SimpleApplication { + + public static void main(String... args) { + TestTangentCube app = new TestTangentCube(); + app.start(); + } + + @Override + public void simpleInitApp() { + Box aBox = new Box(1, 1, 1); + Geometry aGeometry = new Geometry("Box", aBox); + TangentBinormalGenerator.generate(aBox); + + Material aMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + aMaterial.setTexture("DiffuseMap", + assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); + aMaterial.setTexture("NormalMap", + assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg")); + aMaterial.setBoolean("UseMaterialColors", false); + aMaterial.setColor("Diffuse", ColorRGBA.White); + aMaterial.setColor("Specular", ColorRGBA.White); + aMaterial.setFloat("Shininess", 64f); + aGeometry.setMaterial(aMaterial); + + // Rotate 45 degrees to see multiple faces + aGeometry.rotate(FastMath.QUARTER_PI, FastMath.QUARTER_PI, 0.0f); + rootNode.attachChild(aGeometry); + + /** + * Must add a light to make the lit object visible! + */ + PointLight aLight = new PointLight(); + aLight.setPosition(new Vector3f(0, 3, 3)); + aLight.setColor(ColorRGBA.Red); + rootNode.addLight(aLight); +// +// AmbientLight bLight = new AmbientLight(); +// bLight.setColor(ColorRGBA.Gray); +// rootNode.addLight(bLight); + + + ChaseCameraAppState chaser = new ChaseCameraAppState(); + chaser.setTarget(aGeometry); + getStateManager().attach(chaser); + } + +} diff --git a/JmeTests/src/jme3test/light/TestTangentGen.java b/JmeTests/src/jme3test/light/TestTangentGen.java new file mode 100644 index 0000000..042a857 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTangentGen.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.BufferUtils; +import com.jme3.util.TangentBinormalGenerator; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + + +public class TestTangentGen extends SimpleApplication { + + float angle; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestTangentGen app = new TestTangentGen(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(20); + Sphere sphereMesh = new Sphere(32, 32, 1); + sphereMesh.setTextureMode(Sphere.TextureMode.Projected); + sphereMesh.updateGeometry(32, 32, 1, false, false); + addMesh("Sphere", sphereMesh, new Vector3f(-1, 0, 0)); + + Quad quadMesh = new Quad(1, 1); + quadMesh.updateGeometry(1, 1); + addMesh("Quad", quadMesh, new Vector3f(1, 0, 0)); + + Mesh strip = createTriangleStripMesh(); + addMesh("strip", strip, new Vector3f(0, -3, 0)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -1, -1).normalizeLocal()); + dl.setColor(ColorRGBA.White); + rootNode.addLight(dl); + } + + private void addMesh(String name, Mesh mesh, Vector3f translation) { + TangentBinormalGenerator.generate(mesh); + + Geometry testGeom = new Geometry(name, mesh); + Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m"); + testGeom.setMaterial(mat); + testGeom.getLocalTranslation().set(translation); + rootNode.attachChild(testGeom); + + Geometry debug = new Geometry( + "Debug " + name, + TangentBinormalGenerator.genTbnLines(mesh, 0.08f) + ); + Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m"); + debug.setMaterial(debugMat); + debug.setCullHint(Spatial.CullHint.Never); + debug.getLocalTranslation().set(translation); + rootNode.attachChild(debug); + } + + @Override + public void simpleUpdate(float tpf){ + } + + private Mesh createTriangleStripMesh() { + Mesh strip = new Mesh(); + strip.setMode(Mode.TriangleStrip); + FloatBuffer vb = BufferUtils.createFloatBuffer(3*3*3); // 3 rows * 3 columns * 3 floats + vb.rewind(); + vb.put(new float[]{0,2,0}); vb.put(new float[]{1,2,0}); vb.put(new float[]{2,2,0}); + vb.put(new float[]{0,1,0}); vb.put(new float[]{1,1,0}); vb.put(new float[]{2,1,0}); + vb.put(new float[]{0,0,0}); vb.put(new float[]{1,0,0}); vb.put(new float[]{2,0,0}); + FloatBuffer nb = BufferUtils.createFloatBuffer(3*3*3); + nb.rewind(); + nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); + nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); + nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); + FloatBuffer tb = BufferUtils.createFloatBuffer(3*3*2); + tb.rewind(); + tb.put(new float[]{0,0}); tb.put(new float[]{0.5f,0}); tb.put(new float[]{1,0}); + tb.put(new float[]{0,0.5f}); tb.put(new float[]{0.5f,0.5f}); tb.put(new float[]{1,0.5f}); + tb.put(new float[]{0,1}); tb.put(new float[]{0.5f,1}); tb.put(new float[]{1,1}); + int[] indexes = new int[]{0,3,1,4,2,5, 5,3, 3,6,4,7,5,8}; + IntBuffer ib = BufferUtils.createIntBuffer(indexes.length); + ib.put(indexes); + strip.setBuffer(Type.Position, 3, vb); + strip.setBuffer(Type.Normal, 3, nb); + strip.setBuffer(Type.TexCoord, 2, tb); + strip.setBuffer(Type.Index, 3, ib); + strip.updateBound(); + return strip; + } + +} diff --git a/JmeTests/src/jme3test/light/TestTangentGenBadModels.java b/JmeTests/src/jme3test/light/TestTangentGenBadModels.java new file mode 100644 index 0000000..21817e7 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTangentGenBadModels.java @@ -0,0 +1,135 @@ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.*; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +/** + * + * @author Kirusha + */ +public class TestTangentGenBadModels extends SimpleApplication { + + float angle; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestTangentGenBadModels app = new TestTangentGenBadModels(); + app.start(); + } + + @Override + public void simpleInitApp() { +// assetManager.registerLocator("http://jme-glsl-shaders.googlecode.com/hg/assets/Models/LightBlow/", UrlLocator.class); +// assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/", UrlLocator.class); + + final Spatial badModel = assetManager.loadModel("Models/TangentBugs/test.blend"); +// badModel.setLocalScale(1f); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setTexture("NormalMap", assetManager.loadTexture("Models/TangentBugs/test_normal.png")); +// Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m"); + badModel.setMaterial(mat); + rootNode.attachChild(badModel); + + // TODO: For some reason blender loader fails to load this. + // need to check it +// Spatial model = assetManager.loadModel("test.blend"); +// rootNode.attachChild(model); + + final Node debugTangents = new Node("debug tangents"); + debugTangents.setCullHint(CullHint.Always); + rootNode.attachChild(debugTangents); + + final Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m"); + + badModel.depthFirstTraversal(new SceneGraphVisitorAdapter(){ + @Override + public void visit(Geometry g){ + Mesh m = g.getMesh(); + Material mat = g.getMaterial(); + +// if (mat.getParam("DiffuseMap") != null){ +// mat.setTexture("DiffuseMap", null); +// } + TangentBinormalGenerator.generate(m); + + Geometry debug = new Geometry( + "debug tangents geom", + TangentBinormalGenerator.genTbnLines(g.getMesh(), 0.2f) + ); + debug.setMaterial(debugMat); + debug.setCullHint(Spatial.CullHint.Never); + debug.setLocalTransform(g.getWorldTransform()); + debugTangents.attachChild(debug); + } + }); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.8f, -0.6f, -0.08f).normalizeLocal()); + dl.setColor(new ColorRGBA(1,1,1,1)); + rootNode.addLight(dl); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.getMesh().setStatic(); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); +// rootNode.addLight(pl); + + + BitmapText info = new BitmapText(guiFont); + info.setText("Press SPACE to switch between lighting and tangent display"); + info.setQueueBucket(Bucket.Gui); + info.move(0, settings.getHeight() - info.getLineHeight(), 0); + rootNode.attachChild(info); + + inputManager.addMapping("space", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(new ActionListener() { + + private boolean isLit = true; + + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) return; + Material mat; + if (isLit){ + mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m"); + debugTangents.setCullHint(CullHint.Inherit); + }else{ + mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setTexture("NormalMap", assetManager.loadTexture("Models/TangentBugs/test_normal.png")); + debugTangents.setCullHint(CullHint.Always); + } + isLit = !isLit; + badModel.setMaterial(mat); + } + }, "space"); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 2f, FastMath.sin(angle) * 2f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + + +} diff --git a/JmeTests/src/jme3test/light/TestTangentGenBadUV.java b/JmeTests/src/jme3test/light/TestTangentGenBadUV.java new file mode 100644 index 0000000..6b7a630 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTangentGenBadUV.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +public class TestTangentGenBadUV extends SimpleApplication { + + float angle; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestTangentGenBadUV app = new TestTangentGenBadUV(); + app.start(); + } + + @Override + public void simpleInitApp() { + Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + if (teapot instanceof Geometry){ + Geometry g = (Geometry) teapot; + TangentBinormalGenerator.generate(g.getMesh()); + }else{ + throw new RuntimeException(); + } + teapot.setLocalScale(2f); + Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m"); + teapot.setMaterial(mat); + rootNode.attachChild(teapot); + + Geometry debug = new Geometry( + "Debug Teapot", + TangentBinormalGenerator.genTbnLines(((Geometry) teapot).getMesh(), 0.03f) + ); + Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m"); + debug.setMaterial(debugMat); + debug.setCullHint(Spatial.CullHint.Never); + debug.getLocalTranslation().set(teapot.getLocalTranslation()); + debug.getLocalScale().set(teapot.getLocalScale()); + rootNode.attachChild(debug); + + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1,-1,-1).normalizeLocal()); + dl.setColor(ColorRGBA.White); + rootNode.addLight(dl); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.getMesh().setStatic(); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); + //pl.setRadius(3f); + rootNode.addLight(pl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 0.5f, FastMath.sin(angle) * 2f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/light/TestTangentSpace.java b/JmeTests/src/jme3test/light/TestTangentSpace.java new file mode 100644 index 0000000..9f8daf8 --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTangentSpace.java @@ -0,0 +1,100 @@ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.*; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.util.TangentBinormalGenerator; +import com.jme3.util.mikktspace.MikktspaceTangentGenerator; + +/** + * test + * + * @author normenhansen + */ +public class TestTangentSpace extends SimpleApplication { + + public static void main(String[] args) { + TestTangentSpace app = new TestTangentSpace(); + app.start(); + } + + private Node debugNode = new Node("debug"); + + @Override + public void simpleInitApp() { + renderManager.setSinglePassLightBatchSize(2); + renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); + initView(); + + Spatial s = assetManager.loadModel("Models/Test/BasicCubeLow.obj"); + rootNode.attachChild(s); + + Material m = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + m.setTexture("NormalMap", assetManager.loadTexture("Models/Test/Normal_pixel.png")); + + Geometry g = (Geometry)s; + Geometry g2 = (Geometry) g.deepClone(); + g2.move(5, 0, 0); + g.getParent().attachChild(g2); + + g.setMaterial(m); + g2.setMaterial(m); + + //Regular tangent generation (left geom) + TangentBinormalGenerator.generate(g2.getMesh(), true); + + //MikkTSPace Tangent generation (right geom) + + MikktspaceTangentGenerator.generate(g); + + createDebugTangents(g2); + createDebugTangents(g); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggleDebug") && isPressed) { + if (debugNode.getParent() == null) { + rootNode.attachChild(debugNode); + } else { + debugNode.removeFromParent(); + } + } + } + }, "toggleDebug"); + + inputManager.addMapping("toggleDebug", new KeyTrigger(KeyInput.KEY_SPACE)); + + + DirectionalLight dl = new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + } + + private void initView() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + cam.setLocation(new Vector3f(8.569681f, 3.335546f, 5.4372444f)); + cam.setRotation(new Quaternion(-0.07608022f, 0.9086564f, -0.18992864f, -0.3639813f)); + flyCam.setMoveSpeed(10); + } + + private void createDebugTangents(Geometry geom) { + Geometry debug = new Geometry( + "Debug " + geom.getName(), + TangentBinormalGenerator.genTbnLines(geom.getMesh(), 0.8f) + ); + Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m"); + debug.setMaterial(debugMat); + debug.setCullHint(Spatial.CullHint.Never); + debug.getLocalTranslation().set(geom.getWorldTranslation()); + debugNode.attachChild(debug); + } +} diff --git a/JmeTests/src/jme3test/light/TestTransparentShadow.java b/JmeTests/src/jme3test/light/TestTransparentShadow.java new file mode 100644 index 0000000..23fe73c --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTransparentShadow.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.CompareMode; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.util.TangentBinormalGenerator; + +public class TestTransparentShadow extends SimpleApplication { + + public static void main(String[] args){ + TestTransparentShadow app = new TestTransparentShadow(); + app.start(); + } + + public void simpleInitApp() { + cam.setLocation(new Vector3f(5.700248f, 6.161693f, 5.1404157f)); + cam.setRotation(new Quaternion(-0.09441641f, 0.8993388f, -0.24089815f, -0.35248178f)); + + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + Quad q = new Quad(20, 20); + q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(10)); + TangentBinormalGenerator.generate(q); + Geometry geom = new Geometry("floor", q); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + geom.setMaterial(mat); + + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.center(); + geom.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(geom); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.7f)); + rootNode.addLight(al); + + DirectionalLight dl1 = new DirectionalLight(); + dl1.setDirection(new Vector3f(0, -1, 0.5f).normalizeLocal()); + dl1.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(dl1); + + // create the geometry and attach it + Spatial tree = assetManager.loadModel("Models/Tree/Tree.mesh.j3o"); + tree.setQueueBucket(Bucket.Transparent); + tree.setShadowMode(ShadowMode.CastAndReceive); + + rootNode.attachChild(tree); + + // Uses Texture from jme3-test-data library! + ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30); + Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + fire.setShadowMode(ShadowMode.Cast); + fire.setMaterial(mat_red); + fire.setImagesX(2); + fire.setImagesY(2); // 2x2 texture animation + fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red + fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow + fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0)); + fire.setStartSize(0.6f); + fire.setEndSize(0.1f); + fire.setGravity(0, 0, 0); + fire.setLowLife(0.5f); + fire.setHighLife(1.5f); + fire.getParticleInfluencer().setVelocityVariation(0.3f); + fire.setLocalTranslation(5.0f, 0, 1.0f); + fire.setLocalScale(0.3f); + fire.setQueueBucket(Bucket.Translucent); + rootNode.attachChild(fire); + + Material mat2 = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + + Geometry ball = new Geometry("sphere", new Sphere(16, 16, 0.5f)); + ball.setMaterial(mat2); + ball.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(ball); + ball.setLocalTranslation(-1.0f, 1.5f, 1.0f); + + final DirectionalLightShadowRenderer dlsRenderer = new DirectionalLightShadowRenderer(assetManager, 1024, 1); + dlsRenderer.setLight(dl1); + dlsRenderer.setLambda(0.55f); + dlsRenderer.setShadowIntensity(0.8f); + dlsRenderer.setShadowCompareMode(CompareMode.Software); + dlsRenderer.setEdgeFilteringMode(EdgeFilteringMode.Nearest); + dlsRenderer.displayDebug(); + viewPort.addProcessor(dlsRenderer); + inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B)); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("stabilize") && isPressed) { + dlsRenderer.setEnabledStabilization(!dlsRenderer.isEnabledStabilization()) ; + } + } + }, "stabilize"); + } +} diff --git a/JmeTests/src/jme3test/light/TestTwoSideLighting.java b/JmeTests/src/jme3test/light/TestTwoSideLighting.java new file mode 100644 index 0000000..03fe89e --- /dev/null +++ b/JmeTests/src/jme3test/light/TestTwoSideLighting.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.MaterialDebugAppState; +import com.jme3.util.TangentBinormalGenerator; + +/** + * Checks two sided lighting capability. + * + * @author Kirill Vainer + */ +public class TestTwoSideLighting extends SimpleApplication { + + float angle; + PointLight pl; + Geometry lightMdl; + + public static void main(String[] args){ + TestTwoSideLighting app = new TestTwoSideLighting(); + app.start(); + } + + @Override + public void simpleInitApp() { + // Two-sided lighting requires single pass. + renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); + renderManager.setSinglePassLightBatchSize(4); + + cam.setLocation(new Vector3f(5.936224f, 3.3759952f, -3.3202777f)); + cam.setRotation(new Quaternion(0.16265652f, -0.4811838f, 0.09137692f, 0.8565368f)); + + Geometry quadGeom = new Geometry("quad", new Quad(1, 1)); + quadGeom.move(1, 0, 0); + Material mat1 = assetManager.loadMaterial("Textures/BumpMapTest/SimpleBump.j3m"); + + // Display both front and back faces. + mat1.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off); + + quadGeom.setMaterial(mat1); + // SimpleBump material requires tangents. + TangentBinormalGenerator.generate(quadGeom); + rootNode.attachChild(quadGeom); + + Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.move(-1, 0, 0); + teapot.setLocalScale(2f); + Material mat2 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat2.setFloat("Shininess", 25); + mat2.setBoolean("UseMaterialColors", true); + mat2.setColor("Ambient", ColorRGBA.Black); + mat2.setColor("Diffuse", ColorRGBA.Gray); + mat2.setColor("Specular", ColorRGBA.Gray); + + // Only display backfaces. + mat2.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Front); + + teapot.setMaterial(mat2); + rootNode.attachChild(teapot); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.getMesh().setStatic(); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setRadius(4f); + rootNode.addLight(pl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 3f, 0.5f, FastMath.sin(angle) * 3f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java b/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java new file mode 100644 index 0000000..f0d100e --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light.pbr; + +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.light.LightProbe; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A basic logger for environment map rendering progress. + * @author nehon + */ +public class ConsoleProgressReporter extends JobProgressAdapter{ + + private static final Logger logger = Logger.getLogger(ConsoleProgressReporter.class.getName()); + + long time; + + @Override + public void start() { + time = System.currentTimeMillis(); + logger.log(Level.INFO,"Starting generation"); + } + + @Override + public void progress(double value) { + logger.log(Level.INFO, "Progress : {0}%", (value * 100)); + } + + @Override + public void step(String message) { + logger.info(message); + } + + @Override + public void done(LightProbe result) { + long end = System.currentTimeMillis(); + logger.log(Level.INFO, "Generation done in {0}", ((float)(end - time) / 1000f)); + } + +} diff --git a/JmeTests/src/jme3test/light/pbr/RefEnv.java b/JmeTests/src/jme3test/light/pbr/RefEnv.java new file mode 100644 index 0000000..a88e12b --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/RefEnv.java @@ -0,0 +1,135 @@ +package jme3test.light.pbr; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingSphere; +import com.jme3.environment.EnvironmentCamera; +import com.jme3.environment.LightProbeFactory; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.environment.util.EnvMapUtils; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.LightProbe; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.scene.*; +import com.jme3.ui.Picture; +import com.jme3.util.SkyFactory; + +/** + * test + * + * @author nehon + */ +public class RefEnv extends SimpleApplication { + + private Node tex; + private Node ref; + private Picture refImg; + + public static void main(String[] args) { + RefEnv app = new RefEnv(); + app.start(); + } + + @Override + public void simpleInitApp() { + + cam.setLocation(new Vector3f(-17.95047f, 4.917353f, -17.970531f)); + cam.setRotation(new Quaternion(0.11724457f, 0.29356146f, -0.03630452f, 0.94802815f)); +// cam.setLocation(new Vector3f(14.790441f, 7.164179f, 19.720007f)); +// cam.setRotation(new Quaternion(-0.038261678f, 0.9578362f, -0.15233073f, -0.24058504f)); + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(5); + Spatial sc = assetManager.loadModel("Scenes/PBR/ref/scene.gltf"); + rootNode.attachChild(sc); + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); + rootNode.attachChild(sky); + rootNode.getChild(0).setCullHint(Spatial.CullHint.Always); + + ref = new Node("reference pictures"); + refImg = new Picture("refImg"); + refImg.setHeight(cam.getHeight()); + refImg.setWidth(cam.getWidth()); + refImg.setImage(assetManager, "jme3test/light/pbr/ref.png", false); + + ref.attachChild(refImg); + + stateManager.attach(new EnvironmentCamera(256, Vector3f.ZERO)); + + inputManager.addMapping("tex", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("switch", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("ref", new KeyTrigger(KeyInput.KEY_R)); + inputManager.addListener(new ActionListener() { + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("tex") && isPressed) { + if (tex == null) { + tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(stateManager.getState(EnvironmentCamera.class).debugEnv, assetManager); + } + if (tex.getParent() == null) { + guiNode.attachChild(tex); + } else { + tex.removeFromParent(); + } + } + + if (name.equals("switch") && isPressed) { + switchMat(rootNode.getChild("Scene")); + } + if (name.equals("ref") && isPressed) { + if (ref.getParent() == null) { + guiNode.attachChild(ref); + } else { + ref.removeFromParent(); + } + } + } + }, "tex", "switch", "ref"); + + } + + private void switchMat(Spatial s) { + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial children : n.getChildren()) { + switchMat(children); + } + } else if (s instanceof Geometry) { + Geometry g = (Geometry) s; + Material mat = g.getMaterial(); + if (((Float) mat.getParam("Metallic").getValue()) == 1f) { + mat.setFloat("Metallic", 0); + mat.setColor("BaseColor", ColorRGBA.Black); + ref.attachChild(refImg); + } else { + mat.setFloat("Metallic", 1); + mat.setColor("BaseColor", ColorRGBA.White); + refImg.removeFromParent(); + } + } + } + + private int frame = 0; + + @Override + public void simpleUpdate(float tpf) { + frame++; + + if (frame == 2) { + final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, EnvMapUtils.GenerationType.Fast, new JobProgressAdapter() { + + @Override + public void done(LightProbe result) { + System.err.println("Done rendering env maps"); + tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); + rootNode.getChild(0).setCullHint(Spatial.CullHint.Dynamic); + } + }); + ((BoundingSphere) probe.getBounds()).setRadius(100); + rootNode.addLight(probe); + + } + } +} diff --git a/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java b/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java new file mode 100644 index 0000000..26cae09 --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light.pbr; + +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingSphere; +import com.jme3.environment.EnvironmentCamera; +import com.jme3.environment.LightProbeFactory; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.environment.util.EnvMapUtils; +import com.jme3.environment.util.LightsDebugState; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.light.LightProbe; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.scene.*; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.util.MaterialDebugAppState; +import com.jme3.util.SkyFactory; +import com.jme3.util.mikktspace.MikktspaceTangentGenerator; + +/** + * A test case for PBR lighting. + * Still experimental. + * + * @author nehon + */ +public class TestPBRDirectLighting extends SimpleApplication { + + public static void main(String[] args) { + TestPBRDirectLighting app = new TestPBRDirectLighting(); + app.start(); + } + + private DirectionalLight dl; + + private float roughness = 0.0f; + + @Override + public void simpleInitApp() { + + + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + dl.setColor(ColorRGBA.White); + + ChaseCameraAppState chaser = new ChaseCameraAppState(); + chaser.setDragToRotate(true); + chaser.setMinVerticalRotation(-FastMath.HALF_PI); + chaser.setMaxDistance(1000); + chaser.setInvertVerticalAxis(true); + getStateManager().attach(chaser); + chaser.setTarget(rootNode); + flyCam.setEnabled(false); + + Geometry sphere = new Geometry("sphere", new Sphere(32, 32, 1)); + final Material m = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); + m.setColor("BaseColor", ColorRGBA.Black); + m.setFloat("Metallic", 0f); + m.setFloat("Roughness", roughness); + sphere.setMaterial(m); + rootNode.attachChild(sphere); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + + if (name.equals("rup") && isPressed) { + roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f); + m.setFloat("Roughness", roughness); + } + if (name.equals("rdown") && isPressed) { + roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f); + m.setFloat("Roughness", roughness); + } + + if (name.equals("light") && isPressed) { + dl.setDirection(cam.getDirection().normalize()); + } + } + }, "light", "rup", "rdown"); + + + inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_DOWN)); + + + } + + @Override + public void simpleUpdate(float tpf) { + } + +} + diff --git a/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java b/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java new file mode 100644 index 0000000..5cb276a --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light.pbr; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingSphere; +import com.jme3.environment.EnvironmentCamera; +import com.jme3.environment.LightProbeFactory; +import com.jme3.environment.generation.JobProgressAdapter; +import com.jme3.environment.util.EnvMapUtils; +import com.jme3.environment.util.LightsDebugState; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.light.LightProbe; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.scene.*; +import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.util.MaterialDebugAppState; +import com.jme3.util.SkyFactory; +import com.jme3.util.mikktspace.MikktspaceTangentGenerator; + +/** + * A test case for PBR lighting. + * Still experimental. + * + * @author nehon + */ +public class TestPBRLighting extends SimpleApplication { + + public static void main(String[] args) { + TestPBRLighting app = new TestPBRLighting(); + app.start(); + } + + private Node tex; + + private Geometry model; + private DirectionalLight dl; + private Node modelNode; + private int frame = 0; + private Material pbrMat; + private float roughness = 1.0f; + + @Override + public void simpleInitApp() { + assetManager.registerLoader(KTXLoader.class, "ktx"); + + viewPort.setBackgroundColor(ColorRGBA.White); + modelNode = (Node) new Node("modelNode"); + model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o"); + MikktspaceTangentGenerator.generate(model); + modelNode.attachChild(model); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + dl.setColor(ColorRGBA.White); + rootNode.attachChild(modelNode); + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); +// fpp.addFilter(new FXAAFilter()); + fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(4.0f))); +// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f)); + viewPort.addProcessor(fpp); + + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap); + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap); + //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap); + rootNode.attachChild(sky); + + pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m"); + model.setMaterial(pbrMat); + + + final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0)); + stateManager.attach(envCam); + +// EnvironmentManager envManager = new EnvironmentManager(); +// stateManager.attach(envManager); + + // envManager.setScene(rootNode); + + LightsDebugState debugState = new LightsDebugState(); + stateManager.attach(debugState); + + ChaseCamera chaser = new ChaseCamera(cam, modelNode, inputManager); + chaser.setDragToRotate(true); + chaser.setMinVerticalRotation(-FastMath.HALF_PI); + chaser.setMaxDistance(1000); + chaser.setSmoothMotion(true); + chaser.setRotationSensitivity(10); + chaser.setZoomSensitivity(5); + flyCam.setEnabled(false); + //flyCam.setMoveSpeed(100); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("debug") && isPressed) { + if (tex == null) { + return; + } + if (tex.getParent() == null) { + guiNode.attachChild(tex); + } else { + tex.removeFromParent(); + } + } + + if (name.equals("rup") && isPressed) { + roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f); + pbrMat.setFloat("Roughness", roughness); + } + if (name.equals("rdown") && isPressed) { + roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f); + pbrMat.setFloat("Roughness", roughness); + } + + + if (name.equals("up") && isPressed) { + model.move(0, tpf * 100f, 0); + } + + if (name.equals("down") && isPressed) { + model.move(0, -tpf * 100f, 0); + } + if (name.equals("left") && isPressed) { + model.move(0, 0, tpf * 100f); + } + if (name.equals("right") && isPressed) { + model.move(0, 0, -tpf * 100f); + } + if (name.equals("light") && isPressed) { + dl.setDirection(cam.getDirection().normalize()); + } + } + }, "toggle", "light", "up", "down", "left", "right", "debug", "rup", "rdown"); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_D)); + inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_G)); + + + MaterialDebugAppState debug = new MaterialDebugAppState(); + debug.registerBinding("Common/MatDefs/Light/PBRLighting.frag", rootNode); + debug.registerBinding("Common/ShaderLib/PBR.glsllib", rootNode); + getStateManager().attach(debug); + + } + + @Override + public void simpleUpdate(float tpf) { + frame++; + + if (frame == 2) { + modelNode.removeFromParent(); + final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() { + + @Override + public void done(LightProbe result) { + System.err.println("Done rendering env maps"); + tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); + } + }); + ((BoundingSphere) probe.getBounds()).setRadius(100); + rootNode.addLight(probe); + //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe); + + } + if (frame > 10 && modelNode.getParent() == null) { + rootNode.attachChild(modelNode); + } + } + +} + diff --git a/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java b/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java new file mode 100644 index 0000000..eb30e2d --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light.pbr; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingSphere; +import com.jme3.input.CameraInput; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseAxisTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; + +import com.jme3.environment.LightProbeFactory; +import com.jme3.environment.EnvironmentCamera; +import com.jme3.environment.util.LightsDebugState; +import com.jme3.light.LightProbe; +import com.jme3.material.TechniqueDef; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.FXAAFilter; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.scene.Node; +import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.util.SkyFactory; +import com.jme3.util.TangentBinormalGenerator; + +public class TestPbrEnv extends SimpleApplication implements ActionListener { + + public static final int SHADOWMAP_SIZE = 1024; + private Spatial[] obj; + private Material[] mat; + private DirectionalLightShadowRenderer dlsr; + private LightsDebugState debugState; + + private EnvironmentCamera envCam; + + private Geometry ground; + private Material matGroundU; + private Material matGroundL; + + private Geometry camGeom; + + public static void main(String[] args) { + TestPbrEnv app = new TestPbrEnv(); + app.start(); + } + + + public void loadScene() { + + renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); + renderManager.setSinglePassLightBatchSize(3); + obj = new Spatial[2]; + // Setup first view + + mat = new Material[2]; + mat[0] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat.j3m"); + //mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + mat[1] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat2.j3m"); +// mat[1].setBoolean("UseMaterialColors", true); +// mat[1].setColor("Ambient", ColorRGBA.White.mult(0.5f)); +// mat[1].setColor("Diffuse", ColorRGBA.White.clone()); + + obj[0] = new Geometry("sphere", new Sphere(30, 30, 2)); + obj[0].setShadowMode(ShadowMode.CastAndReceive); + obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f)); + obj[1].setShadowMode(ShadowMode.CastAndReceive); + TangentBinormalGenerator.generate(obj[1]); + TangentBinormalGenerator.generate(obj[0]); + +// for (int i = 0; i < 60; i++) { +// Spatial t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false); +// t.setName("Cube" + i); +// t.setLocalScale(FastMath.nextRandomFloat() * 10f); +// t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]); +// rootNode.attachChild(t); +// t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f)); +// } + + for (int i = 0; i < 2; i++) { + Spatial t = obj[0].clone(false); + t.setName("Cube" + i); + t.setLocalScale( 10f); + t.setMaterial(mat[1].clone()); + rootNode.attachChild(t); + t.setLocalTranslation(i * 200f+ 100f, 50, 800f * (i)); + } + + Box b = new Box(1000, 2, 1000); + b.scaleTextureCoordinates(new Vector2f(20, 20)); + ground = new Geometry("soil", b); + TangentBinormalGenerator.generate(ground); + ground.setLocalTranslation(0, 10, 550); + matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matGroundU.setColor("Color", ColorRGBA.Green); + +// matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); +// Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); +// grass.setWrap(WrapMode.Repeat); +// matGroundL.setTexture("DiffuseMap", grass); + + matGroundL = assetManager.loadMaterial("jme3test/light/pbr/pbrMat4.j3m"); + + ground.setMaterial(matGroundL); + + //ground.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(ground); + + l = new DirectionalLight(); + l.setColor(ColorRGBA.White); + //l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal()); + l.setDirection(new Vector3f(-0.2823181f, -0.41889593f, 0.863031f).normalizeLocal()); + + rootNode.addLight(l); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.5f)); + // rootNode.addLight(al); + + //Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap); + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); + sky.setLocalScale(350); + + rootNode.attachChild(sky); + } + DirectionalLight l; + + @Override + public void simpleInitApp() { + assetManager.registerLoader(KTXLoader.class, "ktx"); + + + // put the camera in a bad position + cam.setLocation(new Vector3f(-52.433647f, 68.69636f, -118.60924f)); + cam.setRotation(new Quaternion(0.10294232f, 0.25269797f, -0.027049713f, 0.96167296f)); + + flyCam.setMoveSpeed(100); + + loadScene(); + + dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 4); + dlsr.setLight(l); + //dlsr.setLambda(0.55f); + dlsr.setShadowIntensity(0.5f); + dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); + //dlsr.displayDebug(); + // viewPort.addProcessor(dlsr); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(6.0f))); + SSAOFilter ssao = new SSAOFilter(); + ssao.setIntensity(5); + + fpp.addFilter(ssao); + + BloomFilter bloomFilter = new BloomFilter(); + fpp.addFilter(bloomFilter); + fpp.addFilter(new FXAAFilter()); + //viewPort.addProcessor(fpp); + + initInputs(); + +// envManager = new EnvironmentManager(); +// getStateManager().attach(envManager); +// + envCam = new EnvironmentCamera(); + getStateManager().attach(envCam); + + debugState = new LightsDebugState(); + debugState.setProbeScale(5); + getStateManager().attach(debugState); + + camGeom = new Geometry("camGeom", new Sphere(16, 16, 2)); +// Material m = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); +// m.setColor("Color", ColorRGBA.Green); + Material m = assetManager.loadMaterial("jme3test/light/pbr/pbrMat3.j3m"); + camGeom.setMaterial(m); + camGeom.setLocalTranslation(0, 20, 0); + camGeom.setLocalScale(5); + rootNode.attachChild(camGeom); + + // envManager.setScene(rootNode); + +// MaterialDebugAppState debug = new MaterialDebugAppState(); +// debug.registerBinding("MatDefs/PBRLighting.frag", rootNode); +// getStateManager().attach(debug); + + flyCam.setDragToRotate(true); + setPauseOnLostFocus(false); + + // cam.lookAt(camGeom.getWorldTranslation(), Vector3f.UNIT_Y); + + } + + private void fixFLyCamInputs() { + inputManager.deleteMapping(CameraInput.FLYCAM_LEFT); + inputManager.deleteMapping(CameraInput.FLYCAM_RIGHT); + inputManager.deleteMapping(CameraInput.FLYCAM_UP); + inputManager.deleteMapping(CameraInput.FLYCAM_DOWN); + + inputManager.addMapping(CameraInput.FLYCAM_LEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true)); + + inputManager.addMapping(CameraInput.FLYCAM_RIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false)); + + inputManager.addMapping(CameraInput.FLYCAM_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); + + inputManager.addMapping(CameraInput.FLYCAM_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); + + inputManager.addListener(flyCam, CameraInput.FLYCAM_LEFT, CameraInput.FLYCAM_RIGHT, CameraInput.FLYCAM_UP, CameraInput.FLYCAM_DOWN); + } + + private void initInputs() { + inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M)); + inputManager.addMapping("snapshot", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("fc", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("debugProbe", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addMapping("debugTex", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN)); + inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT)); + inputManager.addMapping("delete", new KeyTrigger(KeyInput.KEY_DELETE)); + + inputManager.addListener(this, "delete","switchGroundMat", "snapshot", "debugTex", "debugProbe", "fc", "up", "down", "left", "right"); + } + + private LightProbe lastProbe; + private Node debugGui ; + + @Override + public void onAction(String name, boolean keyPressed, float tpf) { + + if (name.equals("switchGroundMat") && keyPressed) { + if (ground.getMaterial() == matGroundL) { + ground.setMaterial(matGroundU); + } else { + + ground.setMaterial(matGroundL); + } + } + + if (name.equals("snapshot") && keyPressed) { + envCam.setPosition(camGeom.getWorldTranslation()); + lastProbe = LightProbeFactory.makeProbe(envCam, rootNode, new ConsoleProgressReporter()); + ((BoundingSphere)lastProbe.getBounds()).setRadius(200); + rootNode.addLight(lastProbe); + + } + + if (name.equals("delete") && keyPressed) { + System.err.println(rootNode.getWorldLightList().size()); + rootNode.removeLight(lastProbe); + System.err.println("deleted"); + System.err.println(rootNode.getWorldLightList().size()); + } + + if (name.equals("fc") && keyPressed) { + + flyCam.setEnabled(true); + } + + if (name.equals("debugProbe") && keyPressed) { + debugState.setEnabled(!debugState.isEnabled()); + } + + if (name.equals("debugTex") && keyPressed) { + if(debugGui == null || debugGui.getParent() == null){ + debugGui = lastProbe.getDebugGui(assetManager); + debugGui.setLocalTranslation(10, 200, 0); + guiNode.attachChild(debugGui); + } else if(debugGui != null){ + debugGui.removeFromParent(); + } + } + + if (name.equals("up")) { + up = keyPressed; + } + if (name.equals("down")) { + down = keyPressed; + } + if (name.equals("right")) { + right = keyPressed; + } + if (name.equals("left")) { + left = keyPressed; + } + if (name.equals("fwd")) { + fwd = keyPressed; + } + if (name.equals("back")) { + back = keyPressed; + } + + } + boolean up = false; + boolean down = false; + boolean left = false; + boolean right = false; + boolean fwd = false; + boolean back = false; + float time = 0; + float s = 50f; + boolean initialized = false; + + @Override + public void simpleUpdate(float tpf) { + + if (!initialized) { + fixFLyCamInputs(); + initialized = true; + } + float val = tpf * s; + if (up) { + camGeom.move(0, 0, val); + } + if (down) { + camGeom.move(0, 0, -val); + + } + if (right) { + camGeom.move(-val, 0, 0); + + } + if (left) { + camGeom.move(val, 0, 0); + + } + + } + +} diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat.j3m new file mode 100644 index 0000000..22e50b6 --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/pbrMat.j3m @@ -0,0 +1,13 @@ +Material My Material : Common/MatDefs/Light/PBRLighting.j3md { + MaterialParameters { + Roughness : 0.1 + BaseColor : 1.0 0.2 0.2 1.0 + Metallic : 0.0 + EmissivePower : 0.0 + EmissiveIntensity : 0.0 + Emissive : 1.0 0.8 0.8 1.0 + ParallaxHeight : 0.0 + } + AdditionalRenderState { + } +} diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m new file mode 100644 index 0000000..2414bf3 --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m @@ -0,0 +1,12 @@ +Material My Material : Common/MatDefs/Light/PBRLighting.j3md { + MaterialParameters { + Metallic : 0.0 + Roughness : 0.0 + BaseColor : 0.8 0.81960785 0.39607844 1.0 + EmissiveIntensity : 5.0 + EmissivePower : 2.0 + Emissive : 1.0 0.0 0.0 1.0 + } + AdditionalRenderState { + } +} diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m new file mode 100644 index 0000000..bdf52aa --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m @@ -0,0 +1,9 @@ +Material My Material : Common/MatDefs/Light/PBRLighting.j3md { + MaterialParameters { + BaseColor : 0.6 0.6 0.6 1.0 + Metallic : 1.0 + Roughness : 0.05 + } + AdditionalRenderState { + } +} diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m new file mode 100644 index 0000000..892c9f8 --- /dev/null +++ b/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m @@ -0,0 +1,11 @@ +Material My Material : Common/MatDefs/Light/PBRLighting.j3md { + MaterialParameters { + BaseColorMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg + Roughness : 0.01 + NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal.jpg + Metallic : 1.0 + BaseColor : 1.0 1.0 1.0 1.0 + } + AdditionalRenderState { + } +} diff --git a/JmeTests/src/jme3test/light/pbr/ref.png b/JmeTests/src/jme3test/light/pbr/ref.png new file mode 100644 index 0000000..23ac5e8 Binary files /dev/null and b/JmeTests/src/jme3test/light/pbr/ref.png differ diff --git a/JmeTests/src/jme3test/material/TestBumpModel.java b/JmeTests/src/jme3test/material/TestBumpModel.java new file mode 100644 index 0000000..49028ba --- /dev/null +++ b/JmeTests/src/jme3test/material/TestBumpModel.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.plugins.ogre.OgreMeshKey; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +public class TestBumpModel extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args){ + TestBumpModel app = new TestBumpModel(); + app.start(); + } + + @Override + public void simpleInitApp() { + Spatial signpost = (Spatial) assetManager.loadAsset(new OgreMeshKey("Models/Sign Post/Sign Post.mesh.xml")); + signpost.setMaterial( (Material) assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m")); + TangentBinormalGenerator.generate(signpost); + rootNode.attachChild(signpost); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial( (Material) assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + // flourescent main light + pl = new PointLight(); + pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f)); + rootNode.addLight(pl); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f)); + rootNode.addLight(dl); + + // skylight + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f)); + rootNode.addLight(dl); + + // white ambient light + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf * 0.25f; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/material/TestColoredTexture.java b/JmeTests/src/jme3test/material/TestColoredTexture.java new file mode 100644 index 0000000..7f7c50f --- /dev/null +++ b/JmeTests/src/jme3test/material/TestColoredTexture.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +public class TestColoredTexture extends SimpleApplication { + + private float time = 0; + private ColorRGBA nextColor; + private ColorRGBA prevColor; + private Material mat; + + public static void main(String[] args){ + TestColoredTexture app = new TestColoredTexture(); + app.start(); + } + + @Override + public void simpleInitApp() { + Quad quadMesh = new Quad(512,512); + Geometry quad = new Geometry("Quad", quadMesh); + quad.setQueueBucket(Bucket.Gui); + + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png")); + quad.setMaterial(mat); + guiNode.attachChildAt(quad, 0); + + nextColor = ColorRGBA.randomColor(); + prevColor = ColorRGBA.Black; + } + + @Override + public void simpleUpdate(float tpf){ + time += tpf; + if (time > 1f){ + time -= 1f; + prevColor = nextColor; + nextColor = ColorRGBA.randomColor(); + } + ColorRGBA currentColor = new ColorRGBA(); + currentColor.interpolateLocal(prevColor, nextColor, time); + + mat.setColor("Color", currentColor); + } + +} diff --git a/JmeTests/src/jme3test/material/TestGeometryShader.java b/JmeTests/src/jme3test/material/TestGeometryShader.java new file mode 100644 index 0000000..04c8223 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestGeometryShader.java @@ -0,0 +1,42 @@ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.BufferUtils; + +/** + * Created by michael on 23.02.15. + */ +public class TestGeometryShader extends SimpleApplication { + @Override + public void simpleInitApp() { + Mesh mesh = new Mesh(); + mesh.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(new int[]{1})); + mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(new float[]{0, 0, 0})); + mesh.setMode(Mesh.Mode.Points); + mesh.setBound(new BoundingBox(new Vector3f(0, 0, 0), 10, 10, 10)); + mesh.updateCounts(); + Geometry geometry = new Geometry("Test", mesh); + geometry.updateGeometricState(); + geometry.setMaterial(new Material(assetManager, "Materials/Geom/SimpleGeom.j3md")); + //geometry.getMaterial().getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off); + //geometry.setMaterial(assetManager.loadMaterial("Materials/Geom/SimpleTess.j3md")); + rootNode.attachChild(geometry); + + Geometry geometry1 = new Geometry("T1", new Sphere(10, 10, 1)); + geometry1.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); + rootNode.attachChild(geometry1); + + } + + public static void main(String[] args) { + TestGeometryShader app = new TestGeometryShader(); + app.start(); + } +} diff --git a/JmeTests/src/jme3test/material/TestMatParamOverride.java b/JmeTests/src/jme3test/material/TestMatParamOverride.java new file mode 100644 index 0000000..6124d9e --- /dev/null +++ b/JmeTests/src/jme3test/material/TestMatParamOverride.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009-2017 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.MatParamOverride; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector4f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shader.VarType; + +/** + * Test if {@link MatParamOverride}s are working correctly. + * + * @author Kirill Vainer + */ +public class TestMatParamOverride extends SimpleApplication { + + private Box box = new Box(1, 1, 1); + final MatParamOverride overrideYellow + = new MatParamOverride(VarType.Vector4, "Color", + ColorRGBA.Yellow); + final MatParamOverride overrideWhite + = new MatParamOverride(VarType.Vector4, "Color", + Vector4f.UNIT_XYZW); + final MatParamOverride overrideGray + = new MatParamOverride(VarType.Vector4, "Color", + new Quaternion(0.5f, 0.5f, 0.5f, 1f)); + + public static void main(String[] args) { + TestMatParamOverride app = new TestMatParamOverride(); + app.start(); + } + + private void createBox(float location, ColorRGBA color) { + Geometry geom = new Geometry("Box", box); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", color); + geom.setMaterial(mat); + geom.move(location, 0, 0); + rootNode.attachChild(geom); + } + + @Override + public void simpleInitApp() { + inputManager.setCursorVisible(true); + + createBox(-3, ColorRGBA.Red); + createBox(0, ColorRGBA.Green); + createBox(3, ColorRGBA.Blue); + + System.out.println("Press G, W, Y, or space bar ..."); + inputManager.addMapping("overrideClear", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("overrideGray", new KeyTrigger(KeyInput.KEY_G)); + inputManager.addMapping("overrideWhite", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("overrideYellow", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + if (name.equals("overrideClear")) { + rootNode.clearMatParamOverrides(); + } else if (name.equals("overrideGray")) { + rootNode.clearMatParamOverrides(); + rootNode.addMatParamOverride(overrideGray); + } else if (name.equals("overrideWhite")) { + rootNode.clearMatParamOverrides(); + rootNode.addMatParamOverride(overrideWhite); + } else if (name.equals("overrideYellow")) { + rootNode.clearMatParamOverrides(); + rootNode.addMatParamOverride(overrideYellow); + } + System.out.println(rootNode.getLocalMatParamOverrides()); + } + } + }, "overrideClear", "overrideGray", "overrideWhite", "overrideYellow"); + } +} diff --git a/JmeTests/src/jme3test/material/TestMaterialCompare.java b/JmeTests/src/jme3test/material/TestMaterialCompare.java new file mode 100644 index 0000000..a378551 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestMaterialCompare.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.material; + +import com.jme3.asset.AssetManager; +import com.jme3.asset.TextureKey; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.system.JmeSystem; +import com.jme3.texture.Texture; + +public class TestMaterialCompare { + + public static void main(String[] args) { + AssetManager assetManager = JmeSystem.newAssetManager( + TestMaterialCompare.class.getResource("/com/jme3/asset/Desktop.cfg")); + + // Cloned materials + Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat1.setName("mat1"); + mat1.setColor("Color", ColorRGBA.Blue); + + Material mat2 = mat1.clone(); + mat2.setName("mat2"); + testEquality(mat1, mat2, true); + + // Cloned material with different render states + Material mat3 = mat1.clone(); + mat3.setName("mat3"); + mat3.getAdditionalRenderState().setBlendMode(BlendMode.ModulateX2); + testEquality(mat1, mat3, false); + + // Two separately loaded materials + Material mat4 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + mat4.setName("mat4"); + Material mat5 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + mat5.setName("mat5"); + testEquality(mat4, mat5, true); + + // Comparing same textures + TextureKey originalKey = (TextureKey) mat4.getTextureParam("DiffuseMap").getTextureValue().getKey(); + TextureKey tex1key = new TextureKey("Models/Sign Post/Sign Post.jpg", false); + tex1key.setGenerateMips(true); + + // Texture keys from the original and the loaded texture + // must be identical, otherwise the resultant textures not identical + // and thus materials are not identical! + if (!originalKey.equals(tex1key)){ + System.out.println("TEXTURE KEYS ARE NOT EQUAL"); + } + + Texture tex1 = assetManager.loadTexture(tex1key); + mat4.setTexture("DiffuseMap", tex1); + testEquality(mat4, mat5, true); + + // Change some stuff on the texture and compare, materials no longer equal + tex1.setWrap(Texture.WrapMode.MirroredRepeat); + testEquality(mat4, mat5, false); + + // Comparing different textures + Texture tex2 = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + mat4.setTexture("DiffuseMap", tex2); + testEquality(mat4, mat5, false); + + // Two materials created the same way + Material mat6 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat6.setName("mat6"); + mat6.setColor("Color", ColorRGBA.Blue); + testEquality(mat1, mat6, true); + + // Changing a material param + mat6.setColor("Color", ColorRGBA.Green); + testEquality(mat1, mat6, false); + } + + private static void testEquality(Material mat1, Material mat2, boolean expected) { + if (mat2.contentEquals(mat1)) { + System.out.print(mat1.getName() + " == " + mat2.getName()); + if (expected) { + System.out.println(" EQUAL OK"); + } else { + System.out.println(" EQUAL FAIL!"); + } + } else { + System.out.print(mat1.getName() + " != " + mat2.getName()); + if (!expected) { + System.out.println(" EQUAL OK"); + } else { + System.out.println(" EQUAL FAIL!"); + } + } + if (mat2.hashCode() == mat1.hashCode()){ + System.out.print(mat1.getName() + " == " + mat2.getName()); + if (expected) { + System.out.println(" HASH OK"); + } else { + System.out.println(" HASH FAIL!"); + } + } else { + System.out.print(mat1.getName() + " != " + mat2.getName()); + if (!expected) { + System.out.println(" HASH OK"); + } else { + System.out.println(" HASH FAIL!"); + } + } + } +} diff --git a/JmeTests/src/jme3test/material/TestNormalMapping.java b/JmeTests/src/jme3test/material/TestNormalMapping.java new file mode 100644 index 0000000..c955b34 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestNormalMapping.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +public class TestNormalMapping extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args){ + TestNormalMapping app = new TestNormalMapping(); + app.start(); + } + + @Override + public void simpleInitApp() { + Sphere sphMesh = new Sphere(32, 32, 1); + sphMesh.setTextureMode(Sphere.TextureMode.Projected); + sphMesh.updateGeometry(32, 32, 1, false, false); + TangentBinormalGenerator.generate(sphMesh); + + Geometry sphere = new Geometry("Rock Ball", sphMesh); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + sphere.setMaterial(mat); + rootNode.attachChild(sphere); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setPosition(new Vector3f(0f, 0f, 4f)); + rootNode.addLight(pl); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(new Vector3f(1,-1,1).normalizeLocal()); +// dl.setColor(new ColorRGBA(0.22f, 0.15f, 0.1f, 1.0f)); +// rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf * 0.25f; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/material/TestParallax.java b/JmeTests/src/jme3test/material/TestParallax.java new file mode 100644 index 0000000..cf5263e --- /dev/null +++ b/JmeTests/src/jme3test/material/TestParallax.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.util.SkyFactory; +import com.jme3.util.TangentBinormalGenerator; + +public class TestParallax extends SimpleApplication { + + private final Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); + + public static void main(String[] args) { + TestParallax app = new TestParallax(); + app.start(); + } + + public void setupSkyBox() { + rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap)); + } + DirectionalLight dl; + + public void setupLighting() { + + dl = new DirectionalLight(); + dl.setDirection(lightDir); + dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1)); + rootNode.addLight(dl); + } + Material mat; + + public void setupFloor() { + mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); + + Node floorGeom = new Node("floorGeom"); + Quad q = new Quad(100, 100); + q.scaleTextureCoordinates(new Vector2f(10, 10)); + Geometry g = new Geometry("geom", q); + g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + floorGeom.attachChild(g); + + + TangentBinormalGenerator.generate(floorGeom); + floorGeom.setLocalTranslation(-50, 22, 60); + //floorGeom.setLocalScale(100); + + floorGeom.setMaterial(mat); + rootNode.attachChild(floorGeom); + } + + public void setupSignpost() { + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material matSp = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + TangentBinormalGenerator.generate(signpost); + signpost.setMaterial(matSp); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 23.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(-15.445636f, 30.162927f, 60.252777f)); + cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f)); + flyCam.setMoveSpeed(30); + + setupLighting(); + setupSkyBox(); + setupFloor(); + setupSignpost(); + + inputManager.addListener(new AnalogListener() { + + @Override + public void onAnalog(String name, float value, float tpf) { + if ("heightUP".equals(name)) { + parallaxHeigh += 0.01; + mat.setFloat("ParallaxHeight", parallaxHeigh); + } + if ("heightDown".equals(name)) { + parallaxHeigh -= 0.01; + parallaxHeigh = Math.max(parallaxHeigh, 0); + mat.setFloat("ParallaxHeight", parallaxHeigh); + } + + } + }, "heightUP", "heightDown"); + inputManager.addMapping("heightUP", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addMapping("heightDown", new KeyTrigger(KeyInput.KEY_K)); + + inputManager.addListener(new ActionListener() { + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed && "toggleSteep".equals(name)) { + steep = !steep; + mat.setBoolean("SteepParallax", steep); + } + } + }, "toggleSteep"); + inputManager.addMapping("toggleSteep", new KeyTrigger(KeyInput.KEY_SPACE)); + } + float parallaxHeigh = 0.05f; + float time = 0; + boolean steep = false; + + @Override + public void simpleUpdate(float tpf) { +// time+=tpf; +// lightDir.set(FastMath.sin(time), -1, FastMath.cos(time)); +// bsr.setDirection(lightDir); +// dl.setDirection(lightDir); + } +} diff --git a/JmeTests/src/jme3test/material/TestParallaxPBR.java b/JmeTests/src/jme3test/material/TestParallaxPBR.java new file mode 100644 index 0000000..2a97a70 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestParallaxPBR.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.util.SkyFactory; +import com.jme3.util.TangentBinormalGenerator; + +public class TestParallaxPBR extends SimpleApplication { + + private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); + + public static void main(String[] args) { + TestParallaxPBR app = new TestParallaxPBR(); + app.start(); + } + + public void setupSkyBox() { + rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap)); + } + DirectionalLight dl; + + public void setupLighting() { + + dl = new DirectionalLight(); + dl.setDirection(lightDir); + dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1)); + rootNode.addLight(dl); + } + Material mat; + + public void setupFloor() { + mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWallPBR.j3m"); + //mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWallPBR2.j3m"); + + Node floorGeom = new Node("floorGeom"); + Quad q = new Quad(100, 100); + q.scaleTextureCoordinates(new Vector2f(10, 10)); + Geometry g = new Geometry("geom", q); + g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + floorGeom.attachChild(g); + + + TangentBinormalGenerator.generate(floorGeom); + floorGeom.setLocalTranslation(-50, 22, 60); + //floorGeom.setLocalScale(100); + + floorGeom.setMaterial(mat); + rootNode.attachChild(floorGeom); + } + + public void setupSignpost() { + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + TangentBinormalGenerator.generate(signpost); + signpost.setMaterial(mat); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 23.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(-15.445636f, 30.162927f, 60.252777f)); + cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f)); + flyCam.setMoveSpeed(30); + + + setupLighting(); + setupSkyBox(); + setupFloor(); + setupSignpost(); + + inputManager.addListener(new AnalogListener() { + + public void onAnalog(String name, float value, float tpf) { + if ("heightUP".equals(name)) { + parallaxHeigh += 0.01; + mat.setFloat("ParallaxHeight", parallaxHeigh); + } + if ("heightDown".equals(name)) { + parallaxHeigh -= 0.01; + parallaxHeigh = Math.max(parallaxHeigh, 0); + mat.setFloat("ParallaxHeight", parallaxHeigh); + } + + } + }, "heightUP", "heightDown"); + inputManager.addMapping("heightUP", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addMapping("heightDown", new KeyTrigger(KeyInput.KEY_K)); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed && "toggleSteep".equals(name)) { + steep = !steep; + mat.setBoolean("SteepParallax", steep); + } + } + }, "toggleSteep"); + inputManager.addMapping("toggleSteep", new KeyTrigger(KeyInput.KEY_SPACE)); + } + float parallaxHeigh = 0.05f; + float time = 0; + boolean steep = false; + + @Override + public void simpleUpdate(float tpf) { +// time+=tpf; +// lightDir.set(FastMath.sin(time), -1, FastMath.cos(time)); +// bsr.setDirection(lightDir); +// dl.setDirection(lightDir); + } +} diff --git a/JmeTests/src/jme3test/material/TestShaderNodes.java b/JmeTests/src/jme3test/material/TestShaderNodes.java new file mode 100644 index 0000000..b1683fc --- /dev/null +++ b/JmeTests/src/jme3test/material/TestShaderNodes.java @@ -0,0 +1,43 @@ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.material.Technique; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.shader.Shader; +import com.jme3.texture.Texture; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestShaderNodes extends SimpleApplication { + + public static void main(String[] args) { + TestShaderNodes app = new TestShaderNodes(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(20); + Logger.getLogger("com.jme3").setLevel(Level.WARNING); + Box boxshape1 = new Box(1f, 1f, 1f); + Geometry cube_tex = new Geometry("A Textured Box", boxshape1); + Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); + mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + Technique t = mat.getActiveTechnique(); + + for (Shader.ShaderSource shaderSource : t.getDef().getShader(assetManager, renderer.getCaps(), t.getDynamicDefines()).getSources()) { + System.out.println(shaderSource.getSource()); + } + + mat.setColor("Color", ColorRGBA.Yellow); + mat.setTexture("ColorMap", tex); + cube_tex.setMaterial(mat); + rootNode.attachChild(cube_tex); + } +} diff --git a/JmeTests/src/jme3test/material/TestSimpleBumps.java b/JmeTests/src/jme3test/material/TestSimpleBumps.java new file mode 100644 index 0000000..5be1adf --- /dev/null +++ b/JmeTests/src/jme3test/material/TestSimpleBumps.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +// phong cutoff for light to normal angle > 90? +public class TestSimpleBumps extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args){ + TestSimpleBumps app = new TestSimpleBumps(); + app.start(); + } + + @Override + public void simpleInitApp() { + Quad quadMesh = new Quad(1, 1); + + Geometry sphere = new Geometry("Rock Ball", quadMesh); + Material mat = assetManager.loadMaterial("Textures/BumpMapTest/SimpleBump.j3m"); + sphere.setMaterial(mat); + TangentBinormalGenerator.generate(sphere); + rootNode.attachChild(sphere); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setPosition(new Vector3f(0f, 0f, 4f)); + rootNode.addLight(pl); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(new Vector3f(1, -1, -1).normalizeLocal()); +// dl.setColor(new ColorRGBA(0.22f, 0.15f, 0.1f, 1.0f)); +// rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf * 0.25f; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/material/TestTessellationShader.java b/JmeTests/src/jme3test/material/TestTessellationShader.java new file mode 100644 index 0000000..dbf9381 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestTessellationShader.java @@ -0,0 +1,68 @@ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.shape.Quad; +import com.jme3.util.BufferUtils; + +import java.util.concurrent.Callable; + +/** + * Created by michael on 28.02.15. + */ +public class TestTessellationShader extends SimpleApplication { + Material tessellationMaterial; + int tessFactor=5; + @Override + public void simpleInitApp() { + tessellationMaterial = new Material(getAssetManager(), "Materials/Tess/SimpleTess.j3md"); + tessellationMaterial.setInt("TessellationFactor", tessFactor); + tessellationMaterial.getAdditionalRenderState().setWireframe(true); + Quad quad = new Quad(10, 10); + quad.clearBuffer(VertexBuffer.Type.Index); + quad.setBuffer(VertexBuffer.Type.Index, 4, BufferUtils.createIntBuffer(0, 1, 2, 3)); + quad.setMode(Mesh.Mode.Patch); + quad.setPatchVertexCount(4); + Geometry geometry = new Geometry("tessTest", quad); + geometry.setMaterial(tessellationMaterial); + rootNode.attachChild(geometry); + + getInputManager().addMapping("TessUp", new KeyTrigger(KeyInput.KEY_O)); + getInputManager().addMapping("TessDo", new KeyTrigger(KeyInput.KEY_L)); + getInputManager().addListener(new AnalogListener() { + @Override + public void onAnalog(String name, float value, float tpf) { + if(name.equals("TessUp")){ + tessFactor++; + enqueue(new Callable() { + @Override + public Boolean call() throws Exception { + tessellationMaterial.setInt("TessellationFactor",tessFactor); + return true; + } + }); + } + if(name.equals("TessDo")){ + tessFactor--; + enqueue(new Callable() { + @Override + public Boolean call() throws Exception { + tessellationMaterial.setInt("TessellationFactor",tessFactor); + return true; + } + }); + } + } + },"TessUp","TessDo"); + } + + public static void main(String[] args) { + new TestTessellationShader().start(); + } +} diff --git a/JmeTests/src/jme3test/material/TestUnshadedModel.java b/JmeTests/src/jme3test/material/TestUnshadedModel.java new file mode 100644 index 0000000..826ef44 --- /dev/null +++ b/JmeTests/src/jme3test/material/TestUnshadedModel.java @@ -0,0 +1,44 @@ +package jme3test.material; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +public class TestUnshadedModel extends SimpleApplication { + + public static void main(String[] args){ + TestUnshadedModel app = new TestUnshadedModel(); + app.start(); + } + + @Override + public void simpleInitApp() { + Sphere sphMesh = new Sphere(32, 32, 1); + sphMesh.setTextureMode(Sphere.TextureMode.Projected); + sphMesh.updateGeometry(32, 32, 1, false, false); + TangentBinormalGenerator.generate(sphMesh); + + Geometry sphere = new Geometry("Rock Ball", sphMesh); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + mat.setColor("Ambient", ColorRGBA.DarkGray); + mat.setColor("Diffuse", ColorRGBA.White); + mat.setBoolean("UseMaterialColors", true); + sphere.setMaterial(mat); + rootNode.attachChild(sphere); + + PointLight pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setPosition(new Vector3f(4f, 0f, 0f)); + rootNode.addLight(pl); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White); + rootNode.addLight(al); + } +} diff --git a/JmeTests/src/jme3test/math/TestHalfFloat.java b/JmeTests/src/jme3test/math/TestHalfFloat.java new file mode 100644 index 0000000..1bd9361 --- /dev/null +++ b/JmeTests/src/jme3test/math/TestHalfFloat.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.math; + +import com.jme3.math.FastMath; +import java.util.Scanner; + +public class TestHalfFloat { + public static void main(String[] args){ + Scanner scan = new Scanner(System.in); + while (true){ + System.out.println("Enter float to convert or 'x' to exit: "); + String s = scan.nextLine(); + if (s.equals("x")) + break; + + float flt = Float.valueOf(s); + short half = FastMath.convertFloatToHalf(flt); + float flt2 = FastMath.convertHalfToFloat(half); + + System.out.println("Input float: "+flt); + System.out.println("Result float: "+flt2); + } + } +} diff --git a/JmeTests/src/jme3test/model/TestGltfLoading.java b/JmeTests/src/jme3test/model/TestGltfLoading.java new file mode 100644 index 0000000..3373638 --- /dev/null +++ b/JmeTests/src/jme3test/model/TestGltfLoading.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model; + +import com.jme3.animation.*; +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.*; +import com.jme3.renderer.Limits; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.jme3.scene.debug.custom.SkeletonDebugAppState; + +import java.util.ArrayList; +import java.util.List; + +public class TestGltfLoading extends SimpleApplication { + + Node autoRotate = new Node("autoRotate"); + List assets = new ArrayList<>(); + Node probeNode; + float time = 0; + int assetIndex = 0; + boolean useAutoRotate = false; + private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + int duration = 2; + boolean playAnim = true; + + public static void main(String[] args) { + TestGltfLoading app = new TestGltfLoading(); + app.start(); + } + + /* + WARNING this test case can't wok without the assets, and considering their size, they are not pushed into the repo + you can find them here : + https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 + https://sketchfab.com/features/gltf + You have to copy them in Model/gltf folder in the test-data project. + */ + public void simpleInitApp() { + + SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState(); + getStateManager().attach(skeletonDebugAppState); + + // cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f)); + // cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f)); + cam.setFrustumPerspective(45f, (float) cam.getWidth() / cam.getHeight(), 0.1f, 100f); + renderer.setDefaultAnisotropicFilter(Math.min(renderer.getLimits().get(Limits.TextureAnisotropy), 8)); + setPauseOnLostFocus(false); + + flyCam.setMoveSpeed(5); + flyCam.setDragToRotate(true); + flyCam.setEnabled(false); + viewPort.setBackgroundColor(new ColorRGBA().setAsSrgb(0.2f, 0.2f, 0.2f, 1.0f)); + rootNode.attachChild(autoRotate); + probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o"); + autoRotate.attachChild(probeNode); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(new Vector3f(-1f, -1.0f, -1f).normalizeLocal()); +// dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); +// rootNode.addLight(dl); + +// DirectionalLight dl2 = new DirectionalLight(); +// dl2.setDirection(new Vector3f(1f, 1.0f, 1f).normalizeLocal()); +// dl2.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)); +// rootNode.addLight(dl2); + +// PointLight pl = new PointLight(new Vector3f(5.0f, 5.0f, 5.0f), ColorRGBA.White, 30); +// rootNode.addLight(pl); +// PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50); +// rootNode.addLight(pl1); + +// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1); +// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1); +// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1); +// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f); +//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f); + // loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f); +// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f); +// +// //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f); +// +// loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f); + //loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f); + //loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f); +// loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f); +// //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f); +// loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f); + +// loadModel("Models/gltf/corset/Corset.gltf", new Vector3f(0, -1, 0), 20f); + loadModel("Models/gltf/boxInter/BoxInterleaved.gltf", new Vector3f(0, 0, 0), 1f); + + + probeNode.attachChild(assets.get(0)); + + ChaseCameraAppState chaseCam = new ChaseCameraAppState(); + chaseCam.setTarget(probeNode); + getStateManager().attach(chaseCam); + chaseCam.setInvertHorizontalAxis(true); + chaseCam.setInvertVerticalAxis(true); + chaseCam.setZoomSpeed(0.5f); + chaseCam.setMinVerticalRotation(-FastMath.HALF_PI); + chaseCam.setRotationSpeed(3); + chaseCam.setDefaultDistance(3); + chaseCam.setDefaultVerticalRotation(0.3f); + + inputManager.addMapping("autorotate", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + useAutoRotate = !useAutoRotate; + } + } + }, "autorotate"); + + inputManager.addMapping("toggleAnim", new KeyTrigger(KeyInput.KEY_RETURN)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + playAnim = !playAnim; + if (playAnim) { + playFirstAnim(rootNode); + } else { + stopAnim(rootNode); + } + } + } + }, "toggleAnim"); + + dumpScene(rootNode, 0); + } + + private T findControl(Spatial s, Class controlClass) { + T ctrl = s.getControl(controlClass); + if (ctrl != null) { + return ctrl; + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + ctrl = findControl(spatial, controlClass); + if (ctrl != null) { + return ctrl; + } + } + } + return null; + } + + private void loadModel(String path, Vector3f offset, float scale) { + Spatial s = assetManager.loadModel(path); + s.scale(scale); + s.move(offset); + assets.add(s); + if (playAnim) { + playFirstAnim(s); + } + + SkeletonControl ctrl = findControl(s, SkeletonControl.class); + +// //ctrl.getSpatial().removeControl(ctrl); + if (ctrl == null) { + return; + } + ctrl.setHardwareSkinningPreferred(false); + getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true); +// AnimControl aCtrl = findControl(s, AnimControl.class); +// //ctrl.getSpatial().removeControl(ctrl); +// if (aCtrl == null) { +// return; +// } +// if (aCtrl.getSkeleton() != null) { +// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true); +// } + + } + + private void playFirstAnim(Spatial s) { + + AnimControl control = s.getControl(AnimControl.class); + if (control != null) { +// if (control.getAnimationNames().size() > 0) { +// control.createChannel().setAnim(control.getAnimationNames().iterator().next()); +// } + for (String name : control.getAnimationNames()) { + control.createChannel().setAnim(name); + } + + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + playFirstAnim(spatial); + } + } + } + + private void stopAnim(Spatial s) { + + AnimControl control = s.getControl(AnimControl.class); + if (control != null) { + for (int i = 0; i < control.getNumChannels(); i++) { + AnimChannel ch = control.getChannel(i); + ch.reset(true); + } + control.clearChannels(); + if (control.getSkeleton() != null) { + control.getSkeleton().reset(); + } + + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + stopAnim(spatial); + } + } + } + + @Override + public void simpleUpdate(float tpf) { + + if (!useAutoRotate) { + return; + } + time += tpf; + autoRotate.rotate(0, tpf * 0.5f, 0); + if (time > duration) { + assets.get(assetIndex).removeFromParent(); + assetIndex = (assetIndex + 1) % assets.size(); + if (assetIndex == 0) { + duration = 10; + } + probeNode.attachChild(assets.get(assetIndex)); + time = 0; + } + } + + private void dumpScene(Spatial s, int indent) { + System.err.println(indentString.substring(0, indent) + s.getName() + " (" + s.getClass().getSimpleName() + ") / " + + s.getLocalTransform().getTranslation().toString() + ", " + + s.getLocalTransform().getRotation().toString() + ", " + + s.getLocalTransform().getScale().toString()); + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + dumpScene(spatial, indent + 1); + } + } + } +} diff --git a/JmeTests/src/jme3test/model/TestGltfLoading2.java b/JmeTests/src/jme3test/model/TestGltfLoading2.java new file mode 100644 index 0000000..7988da4 --- /dev/null +++ b/JmeTests/src/jme3test/model/TestGltfLoading2.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model; + +import com.jme3.animation.*; +import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.math.*; +import com.jme3.renderer.Limits; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.jme3.scene.debug.custom.SkeletonDebugAppState; +import com.jme3.scene.plugins.gltf.GltfModelKey; + +import java.util.*; + +public class TestGltfLoading2 extends SimpleApplication { + + Node autoRotate = new Node("autoRotate"); + List assets = new ArrayList<>(); + Node probeNode; + float time = 0; + int assetIndex = 0; + boolean useAutoRotate = false; + private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + int duration = 2; + boolean playAnim = true; + + public static void main(String[] args) { + TestGltfLoading2 app = new TestGltfLoading2(); + app.start(); + } + + /* + WARNING this test case can't wok without the assets, and considering their size, they are not pushed into the repo + you can find them here : + https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 + https://sketchfab.com/features/gltf + You have to copy them in Model/gltf folder in the test-data project. + */ + public void simpleInitApp() { + + SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState(); + getStateManager().attach(skeletonDebugAppState); + + // cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f)); + // cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f)); + cam.setFrustumPerspective(45f, (float) cam.getWidth() / cam.getHeight(), 0.1f, 100f); + renderer.setDefaultAnisotropicFilter(Math.min(renderer.getLimits().get(Limits.TextureAnisotropy), 8)); + setPauseOnLostFocus(false); + + flyCam.setMoveSpeed(5); + flyCam.setDragToRotate(true); + flyCam.setEnabled(false); + viewPort.setBackgroundColor(new ColorRGBA().setAsSrgb(0.2f, 0.2f, 0.2f, 1.0f)); + rootNode.attachChild(autoRotate); + probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o"); + autoRotate.attachChild(probeNode); + +// DirectionalLight dl = new DirectionalLight(); +// dl.setDirection(new Vector3f(-1f, -1.0f, -1f).normalizeLocal()); +// dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); +// rootNode.addLight(dl); + +// DirectionalLight dl2 = new DirectionalLight(); +// dl2.setDirection(new Vector3f(1f, 1.0f, 1f).normalizeLocal()); +// dl2.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)); +// rootNode.addLight(dl2); + +// PointLight pl = new PointLight(new Vector3f(5.0f, 5.0f, 5.0f), ColorRGBA.White, 30); +// rootNode.addLight(pl); +// PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50); +// rootNode.addLight(pl1); + //loadModel("Models/gltf/buffalo/scene.gltf", new Vector3f(0, -1, 0), 0.1f); + //loadModel("Models/gltf/war/scene.gltf", new Vector3f(0, -1, 0), 0.1f); + loadModel("Models/gltf/ganjaarl/scene.gltf", new Vector3f(0, -1, 0), 0.01f); + //loadModel("Models/gltf/hero/scene.gltf", new Vector3f(0, -1, 0), 0.1f); + //loadModel("Models/gltf/mercy/scene.gltf", new Vector3f(0, -1, 0), 0.01f); + //loadModel("Models/gltf/crab/scene.gltf", Vector3f.ZERO, 1); + //loadModel("Models/gltf/manta/scene.gltf", Vector3f.ZERO, 0.2f); +// loadModel("Models/gltf/bone/scene.gltf", Vector3f.ZERO, 0.1f); +// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1); +// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1); +// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1); +// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f); +//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f); + //loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f); +// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f); +// +// //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f); +// + //loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f); + //loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f); + //loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f); + //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f); + //loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f); + +// loadModel("Models/gltf/corset/Corset.gltf", new Vector3f(0, -1, 0), 20f); + // loadModel("Models/gltf/boxInter/BoxInterleaved.gltf", new Vector3f(0, 0, 0), 1f); + + + probeNode.attachChild(assets.get(0)); + + ChaseCameraAppState chaseCam = new ChaseCameraAppState(); + chaseCam.setTarget(probeNode); + getStateManager().attach(chaseCam); + chaseCam.setInvertHorizontalAxis(true); + chaseCam.setInvertVerticalAxis(true); + chaseCam.setZoomSpeed(0.5f); + chaseCam.setMinVerticalRotation(-FastMath.HALF_PI); + chaseCam.setRotationSpeed(3); + chaseCam.setDefaultDistance(3); + chaseCam.setDefaultVerticalRotation(0.3f); + + inputManager.addMapping("autorotate", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + useAutoRotate = !useAutoRotate; + } + } + }, "autorotate"); + + inputManager.addMapping("toggleAnim", new KeyTrigger(KeyInput.KEY_RETURN)); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + playAnim = !playAnim; + if (playAnim) { + playFirstAnim(rootNode); + } else { + stopAnim(rootNode); + } + } + } + }, "toggleAnim"); + inputManager.addMapping("nextAnim", new KeyTrigger(KeyInput.KEY_RIGHT)); + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed && animControl != null) { + AnimChannel c = animControl.getChannel(0); + if (c == null) { + c = animControl.createChannel(); + } + String anim = anims.poll(); + anims.add(anim); + c.setAnim(anim); + } + } + }, "nextAnim"); + + dumpScene(rootNode, 0); + } + + private T findControl(Spatial s, Class controlClass) { + T ctrl = s.getControl(controlClass); + if (ctrl != null) { + return ctrl; + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + ctrl = findControl(spatial, controlClass); + if (ctrl != null) { + return ctrl; + } + } + } + return null; + } + + private void loadModel(String path, Vector3f offset, float scale) { + GltfModelKey k = new GltfModelKey(path); + //k.setKeepSkeletonPose(true); + Spatial s = assetManager.loadModel(k); + s.scale(scale); + s.move(offset); + assets.add(s); + if (playAnim) { + playFirstAnim(s); + } + + SkeletonControl ctrl = findControl(s, SkeletonControl.class); + + // ctrl.getSpatial().removeControl(ctrl); + if (ctrl == null) { + return; + } + //System.err.println(ctrl.getSkeleton().toString()); + //ctrl.setHardwareSkinningPreferred(false); + // getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true); +// AnimControl aCtrl = findControl(s, AnimControl.class); +// //ctrl.getSpatial().removeControl(ctrl); +// if (aCtrl == null) { +// return; +// } +// if (aCtrl.getSkeleton() != null) { +// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true); +// } + + } + + Queue anims = new LinkedList<>(); + AnimControl animControl; + + private void playFirstAnim(Spatial s) { + + AnimControl control = s.getControl(AnimControl.class); + if (control != null) { + anims.clear(); + for (String name : control.getAnimationNames()) { + anims.add(name); + } + if (anims.isEmpty()) { + return; + } + String anim = anims.poll(); + anims.add(anim); + control.createChannel().setAnim(anim); + animControl = control; + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + playFirstAnim(spatial); + } + } + } + + private void stopAnim(Spatial s) { + + AnimControl control = s.getControl(AnimControl.class); + if (control != null) { + for (int i = 0; i < control.getNumChannels(); i++) { + AnimChannel ch = control.getChannel(i); + ch.reset(true); + } + control.clearChannels(); + } + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + stopAnim(spatial); + } + } + } + + @Override + public void simpleUpdate(float tpf) { + + if (!useAutoRotate) { + return; + } + time += tpf; + autoRotate.rotate(0, tpf * 0.5f, 0); + if (time > duration) { + assets.get(assetIndex).removeFromParent(); + assetIndex = (assetIndex + 1) % assets.size(); + if (assetIndex == 0) { + duration = 10; + } + probeNode.attachChild(assets.get(assetIndex)); + time = 0; + } + } + + private void dumpScene(Spatial s, int indent) { + System.err.println(indentString.substring(0, indent) + s.getName() + " (" + s.getClass().getSimpleName() + ") / " + + s.getLocalTransform().getTranslation().toString() + ", " + + s.getLocalTransform().getRotation().toString() + ", " + + s.getLocalTransform().getScale().toString()); + if (s instanceof Node) { + Node n = (Node) s; + for (Spatial spatial : n.getChildren()) { + dumpScene(spatial, indent + 1); + } + } + } +} diff --git a/JmeTests/src/jme3test/model/TestHoverTank.java b/JmeTests/src/jme3test/model/TestHoverTank.java new file mode 100644 index 0000000..648f739 --- /dev/null +++ b/JmeTests/src/jme3test/model/TestHoverTank.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.ChaseCamera; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.LodControl; +import jme3test.post.BloomUI; + +/** + * + * @author Nehon + */ +public class TestHoverTank extends SimpleApplication { + + public static void main(String[] args) { + TestHoverTank app = new TestHoverTank(); + app.start(); + } + + @Override + public void simpleInitApp() { + Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); + + flyCam.setEnabled(false); + ChaseCamera chaseCam = new ChaseCamera(cam, tank, inputManager); + chaseCam.setSmoothMotion(true); + chaseCam.setMaxDistance(100000); + chaseCam.setMinVerticalRotation(-FastMath.PI / 2); + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + Geometry tankGeom = (Geometry) tank.getChild(0); + LodControl control = new LodControl(); + tankGeom.addControl(control); + rootNode.attachChild(tank); + + Vector3f lightDir = new Vector3f(-0.8719428f, -0.46824604f, 0.14304268f); + DirectionalLight dl = new DirectionalLight(); + dl.setColor(new ColorRGBA(1.0f, 0.92f, 0.75f, 1f)); + dl.setDirection(lightDir); + + Vector3f lightDir2 = new Vector3f(0.70518064f, 0.5902297f, -0.39287305f); + DirectionalLight dl2 = new DirectionalLight(); + dl2.setColor(new ColorRGBA(0.7f, 0.85f, 1.0f, 1f)); + dl2.setDirection(lightDir2); + + rootNode.addLight(dl); + rootNode.addLight(dl2); + rootNode.attachChild(tank); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + BloomFilter bf = new BloomFilter(BloomFilter.GlowMode.Objects); + bf.setBloomIntensity(2.0f); + bf.setExposurePower(1.3f); + fpp.addFilter(bf); + BloomUI bui = new BloomUI(inputManager, bf); + viewPort.addProcessor(fpp); + } +} diff --git a/JmeTests/src/jme3test/model/TestMonkeyHead.java b/JmeTests/src/jme3test/model/TestMonkeyHead.java new file mode 100644 index 0000000..c75e221 --- /dev/null +++ b/JmeTests/src/jme3test/model/TestMonkeyHead.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; + +public class TestMonkeyHead extends SimpleApplication { + + float angle; + PointLight pl; + Spatial lightMdl; + + public static void main(String[] args){ + TestMonkeyHead app = new TestMonkeyHead(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + Spatial bumpy = (Spatial) assetManager.loadModel("Models/MonkeyHead/MonkeyHead.mesh.xml"); + rootNode.attachChild(bumpy); + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + // flourescent main light + pl = new PointLight(); + pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f)); + rootNode.addLight(pl); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f)); + rootNode.addLight(dl); + + // skylight + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f)); + rootNode.addLight(dl); + + // white ambient light + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal()); + dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f)); + rootNode.addLight(dl); + } + + @Override + public void simpleUpdate(float tpf){ + angle += tpf * 0.25f; + angle %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f)); + lightMdl.setLocalTranslation(pl.getPosition()); + } + +} diff --git a/JmeTests/src/jme3test/model/TestObjLoading.java b/JmeTests/src/jme3test/model/TestObjLoading.java new file mode 100644 index 0000000..2546fdd --- /dev/null +++ b/JmeTests/src/jme3test/model/TestObjLoading.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; + +/** + * Tests OBJ format loading + */ +public class TestObjLoading extends SimpleApplication { + + public static void main(String[] args){ + TestObjLoading app = new TestObjLoading(); + app.start(); + } + + public void simpleInitApp() { + // create the geometry and attach it + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + + // show normals as material + Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + teaGeom.setMaterial(mat); + + rootNode.attachChild(teaGeom); + } +} diff --git a/JmeTests/src/jme3test/model/TestOgreLoading.java b/JmeTests/src/jme3test/model/TestOgreLoading.java new file mode 100644 index 0000000..47001ea --- /dev/null +++ b/JmeTests/src/jme3test/model/TestOgreLoading.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; + +public class TestOgreLoading extends SimpleApplication { + + float angle1; + float angle2; + PointLight pl; + PointLight p2; + Spatial lightMdl; + Spatial lightMd2; + + public static void main(String[] args) { + TestOgreLoading app = new TestOgreLoading(); + app.start(); + } + + public void simpleInitApp() { +// PointLight pl = new PointLight(); +// pl.setPosition(new Vector3f(10, 10, -10)); +// rootNode.addLight(pl); + flyCam.setMoveSpeed(10f); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + + lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + rootNode.attachChild(lightMdl); + + lightMd2 = new Geometry("Light", new Sphere(10, 10, 0.1f)); + lightMd2.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m")); + rootNode.attachChild(lightMd2); + + + pl = new PointLight(); + pl.setColor(new ColorRGBA(1, 0.9f, 0.9f, 0)); + pl.setPosition(new Vector3f(0f, 0f, 4f)); + rootNode.addLight(pl); + + p2 = new PointLight(); + p2.setColor(new ColorRGBA(0.9f, 1, 0.9f, 0)); + p2.setPosition(new Vector3f(0f, 0f, 3f)); + rootNode.addLight(p2); + + + // create the geometry and attach it + Spatial elephant = (Spatial) assetManager.loadModel("Models/Elephant/Elephant.mesh.xml"); + float scale = 0.05f; + elephant.scale(scale, scale, scale); + rootNode.attachChild(elephant); + } + + @Override + public void simpleUpdate(float tpf) { + angle1 += tpf * 0.25f; + angle1 %= FastMath.TWO_PI; + + angle2 += tpf * 0.50f; + angle2 %= FastMath.TWO_PI; + + pl.setPosition(new Vector3f(FastMath.cos(angle1) * 4f, 0.5f, FastMath.sin(angle1) * 4f)); + p2.setPosition(new Vector3f(FastMath.cos(angle2) * 4f, 0.5f, FastMath.sin(angle2) * 4f)); + lightMdl.setLocalTranslation(pl.getPosition()); + lightMd2.setLocalTranslation(p2.getPosition()); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java b/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java new file mode 100644 index 0000000..b57fc83 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.debug.SkeletonDebugger; + +public class TestAnimBlendBug extends SimpleApplication implements ActionListener { + +// private AnimControl control; + private AnimChannel channel1, channel2; + private String[] animNames; + + private float blendTime = 0.5f; + private float lockAfterBlending = blendTime + 0.25f; + private float blendingAnimationLock; + + public static void main(String[] args) { + TestAnimBlendBug app = new TestAnimBlendBug(); + app.start(); + } + + public void onAction(String name, boolean value, float tpf) { + if (name.equals("One") && value){ + channel1.setAnim(animNames[4], blendTime); + channel2.setAnim(animNames[4], 0); + channel1.setSpeed(0.25f); + channel2.setSpeed(0.25f); + blendingAnimationLock = lockAfterBlending; + } + } + + public void onPreUpdate(float tpf) { + } + + public void onPostUpdate(float tpf) { + } + + @Override + public void simpleUpdate(float tpf) { + // Is there currently a blending underway? + if (blendingAnimationLock > 0f) { + blendingAnimationLock -= tpf; + } + } + + @Override + public void simpleInitApp() { + inputManager.addMapping("One", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addListener(this, "One"); + + flyCam.setMoveSpeed(100f); + cam.setLocation( new Vector3f( 0f, 150f, -325f ) ); + cam.lookAt( new Vector3f( 0f, 100f, 0f ), Vector3f.UNIT_Y ); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + Node model1 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml"); + Node model2 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml"); +// Node model2 = model1.clone(); + + model1.setLocalTranslation(-60, 0, 0); + model2.setLocalTranslation(60, 0, 0); + + AnimControl control1 = model1.getControl(AnimControl.class); + animNames = control1.getAnimationNames().toArray(new String[0]); + channel1 = control1.createChannel(); + + AnimControl control2 = model2.getControl(AnimControl.class); + channel2 = control2.createChannel(); + + SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton1", control1.getSkeleton()); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", ColorRGBA.Red); + mat.setFloat("PointSize", 7f); + mat.getAdditionalRenderState().setDepthTest(false); + skeletonDebug.setMaterial(mat); + model1.attachChild(skeletonDebug); + + skeletonDebug = new SkeletonDebugger("skeleton2", control2.getSkeleton()); + skeletonDebug.setMaterial(mat); + model2.attachChild(skeletonDebug); + + rootNode.attachChild(model1); + rootNode.attachChild(model2); + } + +} diff --git a/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java b/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java new file mode 100644 index 0000000..49c8878 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java @@ -0,0 +1,85 @@ +package jme3test.model.anim; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimationFactory; +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.util.TangentBinormalGenerator; + +public class TestAnimationFactory extends SimpleApplication { + + public static void main(String[] args) { + TestSpatialAnim app = new TestSpatialAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + + AmbientLight al = new AmbientLight(); + rootNode.addLight(al); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + rootNode.addLight(dl); + + // Create model + Box box = new Box(1, 1, 1); + Geometry geom = new Geometry("box", box); + geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); + Node model = new Node("model"); + model.attachChild(geom); + + Box child = new Box(0.5f, 0.5f, 0.5f); + Geometry childGeom = new Geometry("box", child); + childGeom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); + Node childModel = new Node("childmodel"); + childModel.setLocalTranslation(2, 2, 2); + childModel.attachChild(childGeom); + model.attachChild(childModel); + TangentBinormalGenerator.generate(model); + + //creating quite complex animation witht the AnimationHelper + // animation of 6 seconds named "anim" and with 25 frames per second + AnimationFactory animationFactory = new AnimationFactory(6, "anim", 25); + + //creating a translation keyFrame at time = 3 with a translation on the x axis of 5 WU + animationFactory.addTimeTranslation(3, new Vector3f(5, 0, 0)); + //resetting the translation to the start position at time = 6 + animationFactory.addTimeTranslation(6, new Vector3f(0, 0, 0)); + + //Creating a scale keyFrame at time = 2 with the unit scale. + animationFactory.addTimeScale(2, new Vector3f(1, 1, 1)); + //Creating a scale keyFrame at time = 4 scaling to 1.5 + animationFactory.addTimeScale(4, new Vector3f(1.5f, 1.5f, 1.5f)); + //resetting the scale to the start value at time = 5 + animationFactory.addTimeScale(5, new Vector3f(1, 1, 1)); + + + //Creating a rotation keyFrame at time = 0.5 of quarter PI around the Z axis + animationFactory.addTimeRotation(0.5f,new Quaternion().fromAngleAxis(FastMath.QUARTER_PI, Vector3f.UNIT_Z)); + //rotating back to initial rotation value at time = 1 + animationFactory.addTimeRotation(1,Quaternion.IDENTITY); + //Creating a rotation keyFrame at time = 2. Note that i used the Euler angle version because the angle is higher than PI + //this should result in a complete revolution of the spatial around the x axis in 1 second (from 1 to 2) + animationFactory.addTimeRotationAngles(2, FastMath.TWO_PI,0, 0); + + + AnimControl control = new AnimControl(); + control.addAnim(animationFactory.buildAnimation()); + + model.addControl(control); + + rootNode.attachChild(model); + + //run animation + control.createChannel().setAnim("anim"); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java b/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java new file mode 100644 index 0000000..89e6055 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.AnimEventListener; +import com.jme3.animation.LoopMode; +import com.jme3.animation.SkeletonControl; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; + +/** + * Simple application to test an attachments node on the Jaime model. + * + * Derived from {@link jme3test.model.anim.TestOgreAnim}. + */ +public class TestAttachmentsNode extends SimpleApplication + implements AnimEventListener, ActionListener { + + public static void main(String[] args) { + TestAttachmentsNode app = new TestAttachmentsNode(); + app.start(); + } + + private AnimChannel channel; + private AnimControl control; + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(6.4f, 7.5f, 12.8f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(ColorRGBA.White); + rootNode.addLight(dl); + + Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o"); + control = model.getControl(AnimControl.class); + SkeletonControl skeletonControl = model.getControl(SkeletonControl.class); + + model.center(); + model.setLocalScale(5f); + + control.addListener(this); + channel = control.createChannel(); + channel.setAnim("Idle"); + + Box box = new Box(0.3f, 0.02f, 0.02f); + Geometry saber = new Geometry("saber", box); + saber.move(0.4f, 0.05f, 0.01f); + Material red = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + saber.setMaterial(red); + Node n = skeletonControl.getAttachmentsNode("hand.R"); + n.attachChild(saber); + rootNode.attachChild(model); + + inputManager.addListener(this, "Attack"); + inputManager.addMapping("Attack", new KeyTrigger(KeyInput.KEY_SPACE)); + } + + @Override + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + if (animName.equals("Punches")) { + channel.setAnim("Idle", 0.5f); + channel.setLoopMode(LoopMode.DontLoop); + channel.setSpeed(1f); + } + } + + @Override + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } + + @Override + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Attack") && value) { + if (!channel.getAnimationName().equals("Punches")) { + channel.setAnim("Punches", 0.5f); + channel.setLoopMode(LoopMode.Cycle); + channel.setSpeed(0.5f); + } + } + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java b/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java new file mode 100644 index 0000000..ca636c0 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.asset.BlenderKey; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +public class TestBlenderAnim extends SimpleApplication { + + private AnimChannel channel; + private AnimControl control; + + public static void main(String[] args) { + TestBlenderAnim app = new TestBlenderAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + BlenderKey blenderKey = new BlenderKey("Blender/2.4x/BaseMesh_249.blend"); + + Spatial scene = (Spatial) assetManager.loadModel(blenderKey); + rootNode.attachChild(scene); + + Spatial model = this.findNode(rootNode, "BaseMesh_01"); + model.center(); + + control = model.getControl(AnimControl.class); + channel = control.createChannel(); + + channel.setAnim("run_01"); + } + + /** + * This method finds a node of a given name. + * @param rootNode the root node to search + * @param name the name of the searched node + * @return the found node or null + */ + private Spatial findNode(Node rootNode, String name) { + if (name.equals(rootNode.getName())) { + return rootNode; + } + return rootNode.getChild(name); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java b/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java new file mode 100644 index 0000000..b352ec2 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.asset.BlenderKey; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +public class TestBlenderObjectAnim extends SimpleApplication { + + private AnimChannel channel; + private AnimControl control; + + public static void main(String[] args) { + TestBlenderObjectAnim app = new TestBlenderObjectAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + BlenderKey blenderKey = new BlenderKey("Blender/2.4x/animtest.blend"); + + Spatial scene = (Spatial) assetManager.loadModel(blenderKey); + rootNode.attachChild(scene); + + Spatial model = this.findNode(rootNode, "Cube"); + model.center(); + + control = model.getControl(AnimControl.class); + channel = control.createChannel(); + + channel.setAnim("Action"); + } + + /** + * This method finds a node of a given name. + * @param rootNode the root node to search + * @param name the name of the searched node + * @return the found node or null + */ + private Spatial findNode(Node rootNode, String name) { + if (name.equals(rootNode.getName())) { + return rootNode; + } + return rootNode.getChild(name); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestCustomAnim.java b/JmeTests/src/jme3test/model/anim/TestCustomAnim.java new file mode 100644 index 0000000..9340358 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestCustomAnim.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.Bone; +import com.jme3.animation.Skeleton; +import com.jme3.animation.SkeletonControl; +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.VertexBuffer.Format; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.VertexBuffer.Usage; +import com.jme3.scene.shape.Box; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +public class TestCustomAnim extends SimpleApplication { + + private Bone bone; + private Skeleton skeleton; + private Quaternion rotation = new Quaternion(); + + public static void main(String[] args) { + TestCustomAnim app = new TestCustomAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + + AmbientLight al = new AmbientLight(); + rootNode.addLight(al); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + rootNode.addLight(dl); + + Box box = new Box(1, 1, 1); + + VertexBuffer weightsHW = new VertexBuffer(Type.HWBoneWeight); + VertexBuffer indicesHW = new VertexBuffer(Type.HWBoneIndex); + indicesHW.setUsage(Usage.CpuOnly); + weightsHW.setUsage(Usage.CpuOnly); + box.setBuffer(weightsHW); + box.setBuffer(indicesHW); + + // Setup bone weight buffer + FloatBuffer weights = FloatBuffer.allocate( box.getVertexCount() * 4 ); + VertexBuffer weightsBuf = new VertexBuffer(Type.BoneWeight); + weightsBuf.setupData(Usage.CpuOnly, 4, Format.Float, weights); + box.setBuffer(weightsBuf); + + // Setup bone index buffer + ByteBuffer indices = ByteBuffer.allocate( box.getVertexCount() * 4 ); + VertexBuffer indicesBuf = new VertexBuffer(Type.BoneIndex); + indicesBuf.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, indices); + box.setBuffer(indicesBuf); + + // Create bind pose buffers + box.generateBindPose(); + + // Create skeleton + bone = new Bone("root"); + bone.setBindTransforms(Vector3f.ZERO, Quaternion.IDENTITY, Vector3f.UNIT_XYZ); + bone.setUserControl(true); + skeleton = new Skeleton(new Bone[]{ bone }); + + // Assign all verticies to bone 0 with weight 1 + for (int i = 0; i < box.getVertexCount() * 4; i += 4){ + // assign vertex to bone index 0 + indices.array()[i+0] = 0; + indices.array()[i+1] = 0; + indices.array()[i+2] = 0; + indices.array()[i+3] = 0; + + // set weight to 1 only for first entry + weights.array()[i+0] = 1; + weights.array()[i+1] = 0; + weights.array()[i+2] = 0; + weights.array()[i+3] = 0; + } + + // Maximum number of weights per bone is 1 + box.setMaxNumWeights(1); + + // Create model + Geometry geom = new Geometry("box", box); + geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); + Node model = new Node("model"); + model.attachChild(geom); + + // Create skeleton control + SkeletonControl skeletonControl = new SkeletonControl(skeleton); + model.addControl(skeletonControl); + + rootNode.attachChild(model); + } + + @Override + public void simpleUpdate(float tpf){ + // Rotate around X axis + Quaternion rotate = new Quaternion(); + rotate.fromAngleAxis(tpf, Vector3f.UNIT_X); + + // Combine rotation with previous + rotation.multLocal(rotate); + + // Set new rotation into bone + bone.setUserTransforms(Vector3f.ZERO, rotation, Vector3f.UNIT_XYZ); + + // After changing skeleton transforms, must update world data + skeleton.updateWorldVectors(); + } + +} diff --git a/JmeTests/src/jme3test/model/anim/TestHWSkinning.java b/JmeTests/src/jme3test/model/anim/TestHWSkinning.java new file mode 100644 index 0000000..9a2e788 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestHWSkinning.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model.anim; + +import com.jme3.animation.*; +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; +import java.util.ArrayList; +import java.util.List; + +public class TestHWSkinning extends SimpleApplication implements ActionListener{ + + private AnimChannel channel; + private AnimControl control; + private String[] animNames = {"Dodge", "Walk", "pull", "push"}; + private final static int SIZE = 10; + private boolean hwSkinningEnable = true; + private List skControls = new ArrayList(); + private BitmapText hwsText; + + public static void main(String[] args) { + TestHWSkinning app = new TestHWSkinning(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(3.8664846f, 6.2704787f, 9.664585f)); + cam.setRotation(new Quaternion(-0.054774776f, 0.94064945f, -0.27974048f, -0.18418397f)); + makeHudText(); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + model.setLocalScale(0.1f); + model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2); + control = model.getControl(AnimControl.class); + + channel = control.createChannel(); + channel.setAnim(animNames[(i + j) % 4]); + SkeletonControl skeletonControl = model.getControl(SkeletonControl.class); + skeletonControl.setHardwareSkinningPreferred(hwSkinningEnable); + skControls.add(skeletonControl); + rootNode.attachChild(model); + } + } + + inputManager.addListener(this, "toggleHWS"); + inputManager.addMapping("toggleHWS", new KeyTrigger(KeyInput.KEY_SPACE)); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed && name.equals("toggleHWS")){ + hwSkinningEnable = !hwSkinningEnable; + for (SkeletonControl control : skControls) { + control.setHardwareSkinningPreferred(hwSkinningEnable); + hwsText.setText("HWS : "+ hwSkinningEnable); + } + } + } + + private void makeHudText() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + hwsText = new BitmapText(guiFont, false); + hwsText.setSize(guiFont.getCharSet().getRenderedSize()); + hwsText.setText("HWS : "+ hwSkinningEnable); + hwsText.setLocalTranslation(0, cam.getHeight(), 0); + guiNode.attachChild(hwsText); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java b/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java new file mode 100644 index 0000000..7552583 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; + +public class TestModelExportingCloning extends SimpleApplication { + + public static void main(String[] args) { + TestModelExportingCloning app = new TestModelExportingCloning(); + app.start(); + } + + @Override + public void simpleInitApp() { + Spatial s = assetManager.loadModel("Models/gltf/human/human.j3o"); + rootNode.attachChild(s); + + rootNode.addLight(new DirectionalLight(new Vector3f(-1,-1,-1))); + } +} diff --git a/JmeTests/src/jme3test/model/anim/TestOgreAnim.java b/JmeTests/src/jme3test/model/anim/TestOgreAnim.java new file mode 100644 index 0000000..b6bd4cd --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestOgreAnim.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.*; +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; + +public class TestOgreAnim extends SimpleApplication + implements AnimEventListener, ActionListener { + + private AnimChannel channel; + private AnimControl control; + private Geometry geom; + + public static void main(String[] args) { + TestOgreAnim app = new TestOgreAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + model.center(); + + control = model.getControl(AnimControl.class); + control.addListener(this); + channel = control.createChannel(); + + for (String anim : control.getAnimationNames()) + System.out.println(anim); + + channel.setAnim("stand"); + geom = (Geometry)((Node)model).getChild(0); + SkeletonControl skeletonControl = model.getControl(SkeletonControl.class); + + Box b = new Box(.25f,3f,.25f); + Geometry item = new Geometry("Item", b); + item.move(0, 1.5f, 0); + item.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + Node n = skeletonControl.getAttachmentsNode("hand.right"); + n.attachChild(item); + + rootNode.attachChild(model); + + inputManager.addListener(this, "Attack"); + inputManager.addMapping("Attack", new KeyTrigger(KeyInput.KEY_SPACE)); + } + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); +// geom.getMesh().createCollisionData(); + + } + + + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + if (animName.equals("Dodge")){ + channel.setAnim("stand", 0.50f); + channel.setLoopMode(LoopMode.DontLoop); + channel.setSpeed(1f); + } + } + + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Attack") && value){ + if (!channel.getAnimationName().equals("Dodge")){ + channel.setAnim("Dodge", 0.50f); + channel.setLoopMode(LoopMode.Cycle); + channel.setSpeed(0.10f); + } + } + } + +} diff --git a/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java b/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java new file mode 100644 index 0000000..fa12835 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.anim; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.Bone; +import com.jme3.animation.LoopMode; +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.debug.SkeletonDebugger; + +public class TestOgreComplexAnim extends SimpleApplication { + + private AnimControl control; + private float angle = 0; + private float scale = 1; + private float rate = 1; + + public static void main(String[] args) { + TestOgreComplexAnim app = new TestOgreComplexAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + + Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + + control = model.getControl(AnimControl.class); + + AnimChannel feet = control.createChannel(); + AnimChannel leftHand = control.createChannel(); + AnimChannel rightHand = control.createChannel(); + + // feet will dodge + feet.addFromRootBone("hip.right"); + feet.addFromRootBone("hip.left"); + feet.setAnim("Dodge"); + feet.setSpeed(2); + feet.setLoopMode(LoopMode.Cycle); + + // will blend over 15 seconds to stand + feet.setAnim("Walk", 15); + feet.setSpeed(0.25f); + feet.setLoopMode(LoopMode.Cycle); + + // left hand will pull + leftHand.addFromRootBone("uparm.right"); + leftHand.setAnim("pull"); + leftHand.setSpeed(.5f); + + // will blend over 15 seconds to stand + leftHand.setAnim("stand", 15); + + // right hand will push + rightHand.addBone("spinehigh"); + rightHand.addFromRootBone("uparm.left"); + rightHand.setAnim("push"); + + SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton", control.getSkeleton()); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", ColorRGBA.Green); + mat.setFloat("PointSize", 7f); + mat.getAdditionalRenderState().setDepthTest(false); + skeletonDebug.setMaterial(mat); + + model.attachChild(skeletonDebug); + rootNode.attachChild(model); + } + + @Override + public void simpleUpdate(float tpf){ + Bone b = control.getSkeleton().getBone("spinehigh"); + Bone b2 = control.getSkeleton().getBone("uparm.left"); + + angle += tpf * rate; + if (angle > FastMath.HALF_PI / 2f){ + angle = FastMath.HALF_PI / 2f; + rate = -1; + }else if (angle < -FastMath.HALF_PI / 2f){ + angle = -FastMath.HALF_PI / 2f; + rate = 1; + } + + Quaternion q = new Quaternion(); + q.fromAngles(0, angle, 0); + + b.setUserControl(true); + b.setUserTransforms(Vector3f.ZERO, q, Vector3f.UNIT_XYZ); + + b2.setUserControl(true); + b2.setUserTransforms(Vector3f.ZERO, Quaternion.IDENTITY, new Vector3f(1+angle,1+ angle, 1+angle)); + + + } + +} diff --git a/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java b/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java new file mode 100644 index 0000000..6356d2a --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model.anim; + +/** + * + * @author Nehon + */ + + + +import com.jme3.animation.*; +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import java.util.ArrayList; +import java.util.List; +import jme3test.post.SSAOUI; + +public class TestSkeletonControlRefresh extends SimpleApplication implements ActionListener{ + + private AnimChannel channel; + private AnimControl control; + private String[] animNames = {"Dodge", "Walk", "pull", "push"}; + private final static int SIZE = 10; + private boolean hwSkinningEnable = true; + private List skControls = new ArrayList(); + private BitmapText hwsText; + + public static void main(String[] args) { + TestSkeletonControlRefresh app = new TestSkeletonControlRefresh(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.White); + flyCam.setMoveSpeed(10f); + cam.setLocation(new Vector3f(3.8664846f, 6.2704787f, 9.664585f)); + cam.setRotation(new Quaternion(-0.054774776f, 0.94064945f, -0.27974048f, -0.18418397f)); + makeHudText(); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); + rootNode.addLight(dl); + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey k = new TextureKey("Models/Oto/Oto.jpg", false); + m.setTexture("ColorMap", assetManager.loadTexture(k)); + + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + //setting a different material + model.setMaterial(m.clone()); + model.setLocalScale(0.1f); + model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2); + control = model.getControl(AnimControl.class); + + channel = control.createChannel(); + channel.setAnim(animNames[(i + j) % 4]); + channel.setLoopMode(LoopMode.DontLoop); + SkeletonControl skeletonControl = model.getControl(SkeletonControl.class); + + //This is a workaround the issue. this call will make the SkeletonControl gather the targets again. + //skeletonControl.setSpatial(model); + skeletonControl.setHardwareSkinningPreferred(hwSkinningEnable); + skControls.add(skeletonControl); + rootNode.attachChild(model); + } + } + + rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + setupFloor(); + + inputManager.addListener(this, "toggleHWS"); + inputManager.addMapping("toggleHWS", new KeyTrigger(KeyInput.KEY_SPACE)); + +// DirectionalLightShadowRenderer pssm = new DirectionalLightShadowRenderer(assetManager, 1024, 2); +// pssm.setLight(dl); +// viewPort.addProcessor(pssm); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + DirectionalLightShadowFilter sf = new DirectionalLightShadowFilter(assetManager, 1024, 2); + sf.setLight(dl); + fpp.addFilter(sf); + fpp.addFilter(new SSAOFilter()); + viewPort.addProcessor(fpp); + + + } + + public void setupFloor() { + Quad q = new Quad(20, 20); + q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(10)); + Geometry geom = new Geometry("floor", q); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.White); + geom.setMaterial(mat); + + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.center(); + geom.move(0, -0.3f, 0); + geom.setShadowMode(RenderQueue.ShadowMode.Receive); + rootNode.attachChild(geom); + } + + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed && name.equals("toggleHWS")){ + hwSkinningEnable = !hwSkinningEnable; + for (SkeletonControl skControl : skControls) { + skControl.setHardwareSkinningPreferred(hwSkinningEnable); + hwsText.setText("HWS : "+ hwSkinningEnable); + } + } + } + + private void makeHudText() { + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + hwsText = new BitmapText(guiFont, false); + hwsText.setSize(guiFont.getCharSet().getRenderedSize()); + hwsText.setText("HWS : "+ hwSkinningEnable); + hwsText.setLocalTranslation(0, cam.getHeight(), 0); + guiNode.attachChild(hwsText); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java b/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java new file mode 100644 index 0000000..6813803 --- /dev/null +++ b/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java @@ -0,0 +1,87 @@ +package jme3test.model.anim; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.jme3.animation.SpatialTrack; +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import java.util.HashMap; + +public class TestSpatialAnim extends SimpleApplication { + + public static void main(String[] args) { + TestSpatialAnim app = new TestSpatialAnim(); + app.start(); + } + + @Override + public void simpleInitApp() { + + AmbientLight al = new AmbientLight(); + rootNode.addLight(al); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + rootNode.addLight(dl); + + // Create model + Box box = new Box(1, 1, 1); + Geometry geom = new Geometry("box", box); + geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); + Node model = new Node("model"); + model.attachChild(geom); + + Box child = new Box(0.5f, 0.5f, 0.5f); + Geometry childGeom = new Geometry("box", child); + childGeom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m")); + Node childModel = new Node("childmodel"); + childModel.setLocalTranslation(2, 2, 2); + childModel.attachChild(childGeom); + model.attachChild(childModel); + + //animation parameters + float animTime = 5; + int fps = 25; + float totalXLength = 10; + + //calculating frames + int totalFrames = (int) (fps * animTime); + float dT = animTime / totalFrames, t = 0; + float dX = totalXLength / totalFrames, x = 0; + float[] times = new float[totalFrames]; + Vector3f[] translations = new Vector3f[totalFrames]; + Quaternion[] rotations = new Quaternion[totalFrames]; + Vector3f[] scales = new Vector3f[totalFrames]; + for (int i = 0; i < totalFrames; ++i) { + times[i] = t; + t += dT; + translations[i] = new Vector3f(x, 0, 0); + x += dX; + rotations[i] = Quaternion.IDENTITY; + scales[i] = Vector3f.UNIT_XYZ; + } + SpatialTrack spatialTrack = new SpatialTrack(times, translations, rotations, scales); + + //creating the animation + Animation spatialAnimation = new Animation("anim", animTime); + spatialAnimation.setTracks(new SpatialTrack[] { spatialTrack }); + + //create spatial animation control + AnimControl control = new AnimControl(); + HashMap animations = new HashMap(); + animations.put("anim", spatialAnimation); + control.setAnimations(animations); + model.addControl(control); + + rootNode.attachChild(model); + + //run animation + control.createChannel().setAnim("anim"); + } +} diff --git a/JmeTests/src/jme3test/model/shape/TestBillboard.java b/JmeTests/src/jme3test/model/shape/TestBillboard.java new file mode 100644 index 0000000..8fa8a66 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestBillboard.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.BillboardControl; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Quad; + +/** + * + * @author Kirill Vainer + */ +public class TestBillboard extends SimpleApplication { + + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + + Quad q = new Quad(2, 2); + Geometry g = new Geometry("Quad", q); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + g.setMaterial(mat); + + Quad q2 = new Quad(1, 1); + Geometry g3 = new Geometry("Quad2", q2); + Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat2.setColor("Color", ColorRGBA.Yellow); + g3.setMaterial(mat2); + g3.setLocalTranslation(.5f, .5f, .01f); + + Box b = new Box(.25f, .5f, .25f); + Geometry g2 = new Geometry("Box", b); + g2.setLocalTranslation(0, 0, 3); + g2.setMaterial(mat); + + Node bb = new Node("billboard"); + + BillboardControl control=new BillboardControl(); + + bb.addControl(control); + bb.attachChild(g); + bb.attachChild(g3); + + + n=new Node("parent"); + n.attachChild(g2); + n.attachChild(bb); + rootNode.attachChild(n); + + n2=new Node("parentParent"); + n2.setLocalTranslation(Vector3f.UNIT_X.mult(5)); + n2.attachChild(n); + + rootNode.attachChild(n2); + + +// rootNode.attachChild(bb); +// rootNode.attachChild(g2); + } + Node n; + Node n2; + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + n.rotate(0, tpf, 0); + n.move(0.1f*tpf, 0, 0); + n2.rotate(0, 0, -tpf); + } + + + + public static void main(String[] args) { + TestBillboard app = new TestBillboard(); + app.start(); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/model/shape/TestBox.java b/JmeTests/src/jme3test/model/shape/TestBox.java new file mode 100644 index 0000000..0e5e86a --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestBox.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +public class TestBox extends SimpleApplication { + + public static void main(String[] args){ + TestBox app = new TestBox(); + app.start(); + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + +} diff --git a/JmeTests/src/jme3test/model/shape/TestCustomMesh.java b/JmeTests/src/jme3test/model/shape/TestCustomMesh.java new file mode 100644 index 0000000..e11b526 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestCustomMesh.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.util.BufferUtils; + +/** + * How to create custom meshes by specifying vertices + * We render the mesh in three different ways, once with a solid blue color, + * once with vertex colors, and once with a wireframe material. + * @author KayTrance + */ +public class TestCustomMesh extends SimpleApplication { + + public static void main(String[] args){ + TestCustomMesh app = new TestCustomMesh(); + app.start(); + } + + @Override + public void simpleInitApp() { + + Mesh m = new Mesh(); + + // Vertex positions in space + Vector3f [] vertices = new Vector3f[4]; + vertices[0] = new Vector3f(0,0,0); + vertices[1] = new Vector3f(3,0,0); + vertices[2] = new Vector3f(0,3,0); + vertices[3] = new Vector3f(3,3,0); + + // Texture coordinates + Vector2f [] texCoord = new Vector2f[4]; + texCoord[0] = new Vector2f(0,0); + texCoord[1] = new Vector2f(1,0); + texCoord[2] = new Vector2f(0,1); + texCoord[3] = new Vector2f(1,1); + + // Indexes. We define the order in which mesh should be constructed + short[] indexes = {2, 0, 1, 1, 3, 2}; + + // Setting buffers + m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices)); + m.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord)); + m.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indexes)); + m.updateBound(); + + // ************************************************************************* + // First mesh uses one solid color + // ************************************************************************* + + // Creating a geometry, and apply a single color material to it + Geometry geom = new Geometry("OurMesh", m); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + geom.setMaterial(mat); + + // Attaching our geometry to the root node. + rootNode.attachChild(geom); + + // ************************************************************************* + // Second mesh uses vertex colors to color each vertex + // ************************************************************************* + Mesh cMesh = m.clone(); + Geometry coloredMesh = new Geometry ("ColoredMesh", cMesh); + Material matVC = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matVC.setBoolean("VertexColor", true); + + //We have 4 vertices and 4 color values for each of them. + //If you have more vertices, you need 'new float[yourVertexCount * 4]' here! + float[] colorArray = new float[4*4]; + int colorIndex = 0; + + //Set custom RGBA value for each Vertex. Values range from 0.0f to 1.0f + for(int i = 0; i < 4; i++){ + // Red value (is increased by .2 on each next vertex here) + colorArray[colorIndex++]= 0.1f+(.2f*i); + // Green value (is reduced by .2 on each next vertex) + colorArray[colorIndex++]= 0.9f-(0.2f*i); + // Blue value (remains the same in our case) + colorArray[colorIndex++]= 0.5f; + // Alpha value (no transparency set here) + colorArray[colorIndex++]= 1.0f; + } + // Set the color buffer + cMesh.setBuffer(Type.Color, 4, colorArray); + coloredMesh.setMaterial(matVC); + // move mesh a bit so that it doesn't intersect with the first one + coloredMesh.setLocalTranslation(4, 0, 0); + rootNode.attachChild(coloredMesh); + +// /** Alternatively, you can show the mesh vertixes as points +// * instead of coloring the faces. */ +// cMesh.setMode(Mesh.Mode.Points); +// cMesh.setPointSize(10f); +// cMesh.updateBound(); +// cMesh.setStatic(); +// Geometry points = new Geometry("Points", m); +// points.setMaterial(mat); +// rootNode.attachChild(points); + + // ************************************************************************* + // Third mesh will use a wireframe shader to show wireframe + // ************************************************************************* + Mesh wfMesh = m.clone(); + Geometry wfGeom = new Geometry("wireframeGeometry", wfMesh); + Material matWireframe = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWireframe.setColor("Color", ColorRGBA.Green); + matWireframe.getAdditionalRenderState().setWireframe(true); + wfGeom.setMaterial(matWireframe); + wfGeom.setLocalTranslation(4, 4, 0); + rootNode.attachChild(wfGeom); + + } +} diff --git a/JmeTests/src/jme3test/model/shape/TestCylinder.java b/JmeTests/src/jme3test/model/shape/TestCylinder.java new file mode 100644 index 0000000..bec3847 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestCylinder.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Cylinder; +import com.jme3.texture.Texture; + +public class TestCylinder extends SimpleApplication { + + public static void main(String[] args){ + TestCylinder app = new TestCylinder(); + app.start(); + } + + @Override + public void simpleInitApp() { + Cylinder t = new Cylinder(20, 50, 1, 2, true); + Geometry geom = new Geometry("Cylinder", t); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + TextureKey key = new TextureKey("Interface/Logo/Monkey.jpg", true); + key.setGenerateMips(true); + Texture tex = assetManager.loadTexture(key); + tex.setMinFilter(Texture.MinFilter.Trilinear); + mat.setTexture("ColorMap", tex); + + geom.setMaterial(mat); + + rootNode.attachChild(geom); + } + +} diff --git a/JmeTests/src/jme3test/model/shape/TestDebugShapes.java b/JmeTests/src/jme3test/model/shape/TestDebugShapes.java new file mode 100644 index 0000000..fc47316 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestDebugShapes.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.debug.Grid; +import com.jme3.scene.debug.WireBox; +import com.jme3.scene.debug.WireSphere; + +public class TestDebugShapes extends SimpleApplication { + + public static void main(String[] args){ + TestDebugShapes app = new TestDebugShapes(); + app.start(); + } + + public Geometry putShape(Mesh shape, ColorRGBA color, float lineWidth){ + Geometry g = new Geometry("shape", shape); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.getAdditionalRenderState().setLineWidth(lineWidth); + mat.setColor("Color", color); + g.setMaterial(mat); + rootNode.attachChild(g); + return g; + } + + public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){ + Arrow arrow = new Arrow(dir); + putShape(arrow, color, 4).setLocalTranslation(pos); + } + + public void putBox(Vector3f pos, float size, ColorRGBA color){ + putShape(new WireBox(size, size, size), color, 1).setLocalTranslation(pos); + } + + public void putGrid(Vector3f pos, ColorRGBA color){ + putShape(new Grid(6, 6, 0.2f), color, 1).center().move(pos); + } + + public void putSphere(Vector3f pos, ColorRGBA color){ + putShape(new WireSphere(1), color, 1).setLocalTranslation(pos); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(2,1.5f,2)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + + putArrow(Vector3f.ZERO, Vector3f.UNIT_X, ColorRGBA.Red); + putArrow(Vector3f.ZERO, Vector3f.UNIT_Y, ColorRGBA.Green); + putArrow(Vector3f.ZERO, Vector3f.UNIT_Z, ColorRGBA.Blue); + + putBox(new Vector3f(2, 0, 0), 0.5f, ColorRGBA.Yellow); + putGrid(new Vector3f(3.5f, 0, 0), ColorRGBA.White); + putSphere(new Vector3f(4.5f, 0, 0), ColorRGBA.Magenta); + } + +} diff --git a/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java b/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java new file mode 100644 index 0000000..cdab039 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Torus; + +public class TestExpandingTorus extends SimpleApplication { + + private float outerRadius = 1.5f; + private float rate = 1; + private Torus torus; + private Geometry geom; + + public static void main(String[] args) { + TestExpandingTorus app = new TestExpandingTorus(); + app.start(); + } + + @Override + public void simpleInitApp() { + torus = new Torus(30, 10, .5f, 1f); + geom = new Geometry("Torus", torus); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + @Override + public void simpleUpdate(float tpf){ + if (outerRadius > 2.5f){ + outerRadius = 2.5f; + rate = -rate; + }else if (outerRadius < 1f){ + outerRadius = 1f; + rate = -rate; + } + outerRadius += rate * tpf; + torus.updateGeometry(30, 10, .5f, outerRadius); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/model/shape/TestSphere.java b/JmeTests/src/jme3test/model/shape/TestSphere.java new file mode 100644 index 0000000..0bdf0e7 --- /dev/null +++ b/JmeTests/src/jme3test/model/shape/TestSphere.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.model.shape; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; + +public class TestSphere extends SimpleApplication { + + public static void main(String[] args){ + TestSphere app = new TestSphere(); + app.start(); + } + + @Override + public void simpleInitApp() { + Sphere sphMesh = new Sphere(14, 14, 1); + Material solidColor = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + + for (int y = -5; y < 5; y++){ + for (int x = -5; x < 5; x++){ + Geometry sphere = new Geometry("sphere", sphMesh); + sphere.setMaterial(solidColor); + sphere.setLocalTranslation(x * 2, 0, y * 2); + rootNode.attachChild(sphere); + } + } + cam.setLocation(new Vector3f(0, 5, 0)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } + +} diff --git a/JmeTests/src/jme3test/network/MovingAverage.java b/JmeTests/src/jme3test/network/MovingAverage.java new file mode 100644 index 0000000..991b5e5 --- /dev/null +++ b/JmeTests/src/jme3test/network/MovingAverage.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +class MovingAverage { + + private long[] samples; + private long sum; + private int count, index; + + public MovingAverage(int numSamples){ + samples = new long[numSamples]; + } + + public void add(long sample){ + sum = sum - samples[index] + sample; + samples[index++] = sample; + if (index > count){ + count = index; + } + if (index >= samples.length){ + index = 0; + } + } + + public long getAverage(){ + if (count == 0) + return 0; + else + return (long) ((float) sum / (float) count); + } + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/network/TestChatClient.java b/JmeTests/src/jme3test/network/TestChatClient.java new file mode 100644 index 0000000..2e8ecbf --- /dev/null +++ b/JmeTests/src/jme3test/network/TestChatClient.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2011 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.network; + +import com.jme3.network.Client; +import com.jme3.network.ClientStateListener; +import com.jme3.network.ErrorListener; +import com.jme3.network.Message; +import com.jme3.network.MessageListener; +import com.jme3.network.Network; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.*; +import jme3test.network.TestChatServer.ChatMessage; + +/** + * A simple test chat server. When SM implements a set + * of standard chat classes this can become a lot simpler. + * + * @version $Revision$ + * @author Paul Speed + */ +public class TestChatClient extends JFrame { + + private final Client client; + private final JEditorPane chatLog; + private final StringBuilder chatMessages = new StringBuilder(); + private final JTextField nameField; + private final JTextField messageField; + + public TestChatClient(String host) throws IOException { + super("jME3 Test Chat Client - to:" + host); + + // Build out the UI + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setSize(800, 600); + + chatLog = new JEditorPane(); + chatLog.setEditable(false); + chatLog.setContentType("text/html"); + chatLog.setText(""); + + getContentPane().add(new JScrollPane(chatLog), "Center"); + + // A crude form + JPanel p = new JPanel(); + p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); + p.add(new JLabel("Name:")); + nameField = new JTextField(System.getProperty("user.name", "yourname")); + Dimension d = nameField.getPreferredSize(); + nameField.setMaximumSize(new Dimension(120, d.height + 6)); + p.add(nameField); + p.add(new JLabel(" Message:")); + messageField = new JTextField(); + p.add(messageField); + p.add(new JButton(new SendAction(true))); + p.add(new JButton(new SendAction(false))); + + getContentPane().add(p, "South"); + + client = Network.connectToServer(TestChatServer.NAME, TestChatServer.VERSION, + host, TestChatServer.PORT, TestChatServer.UDP_PORT); + client.addMessageListener(new ChatHandler(), ChatMessage.class); + client.addClientStateListener(new ChatClientStateListener()); + client.addErrorListener(new ChatErrorListener()); + client.start(); + + System.out.println("Started client:" + client); + } + + @Override + public void dispose() { + System.out.println("Chat window closing."); + super.dispose(); + if( client.isConnected() ) { + client.close(); + } + } + + public static String getString(Component owner, String title, String message, String initialValue) { + return (String) JOptionPane.showInputDialog(owner, message, title, JOptionPane.PLAIN_MESSAGE, + null, null, initialValue); + } + + public static void main(String... args) throws Exception { + + // Increate the logging level for networking... + System.out.println("Setting logging to max"); + Logger networkLog = Logger.getLogger("com.jme3.network"); + networkLog.setLevel(Level.FINEST); + + // And we have to tell JUL's handler also + // turn up logging in a very convoluted way + Logger rootLog = Logger.getLogger(""); + if( rootLog.getHandlers().length > 0 ) { + rootLog.getHandlers()[0].setLevel(Level.FINEST); + } + + // Note: in JME 3.1 this is generally unnecessary as the server will + // send a message with all server-registered classes. + // TestChatServer.initializeClasses(); + // Leaving the call commented out to be illustrative regarding the + // common old pattern. + + // Grab a host string from the user + String s = getString(null, "Host Info", "Enter chat host:", "localhost"); + if (s == null) { + System.out.println("User cancelled."); + return; + } + + // Register a shutdown hook to get a message on the console when the + // app actually finishes + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + System.out.println("Chat client is terminating."); + } + }); + + + TestChatClient test = new TestChatClient(s); + test.setVisible(true); + } + + private class ChatHandler implements MessageListener { + + @Override + public void messageReceived(Client source, Message m) { + ChatMessage chat = (ChatMessage) m; + + System.out.println("Received:" + chat); + + // One of the least efficient ways to add text to a + // JEditorPane + chatMessages.append("" + (m.isReliable() ? "TCP" : "UDP") + ""); + chatMessages.append(" -- " + chat.getName() + " : "); + chatMessages.append(chat.getMessage()); + chatMessages.append("
"); + String s = "" + chatMessages + ""; + chatLog.setText(s); + + // Set selection to the end so that the scroll panel will scroll + // down. + chatLog.select(s.length(), s.length()); + } + } + + private class ChatClientStateListener implements ClientStateListener { + + @Override + public void clientConnected(Client c) { + System.out.println("clientConnected(" + c + ")"); + } + + @Override + public void clientDisconnected(Client c, DisconnectInfo info) { + System.out.println("clientDisconnected(" + c + "):" + info); + if( info != null ) { + // The connection was closed by the server + JOptionPane.showMessageDialog(rootPane, + info.reason, + "Connection Closed", + JOptionPane.INFORMATION_MESSAGE); + dispose(); + } + } + } + + private class ChatErrorListener implements ErrorListener { + + @Override + public void handleError( Client source, Throwable t ) { + System.out.println("handleError(" + source + ", " + t + ")"); + JOptionPane.showMessageDialog(rootPane, + String.valueOf(t), + "Connection Error", + JOptionPane.ERROR_MESSAGE); + } + + } + + private class SendAction extends AbstractAction { + + private final boolean reliable; + + public SendAction(boolean reliable) { + super(reliable ? "TCP" : "UDP"); + this.reliable = reliable; + } + + @Override + public void actionPerformed(ActionEvent evt) { + String name = nameField.getText(); + String message = messageField.getText(); + + ChatMessage chat = new ChatMessage(name, message); + chat.setReliable(reliable); + System.out.println("Sending:" + chat); + client.send(chat); + } + } +} diff --git a/JmeTests/src/jme3test/network/TestChatClientAndServer.java b/JmeTests/src/jme3test/network/TestChatClientAndServer.java new file mode 100644 index 0000000..0069446 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestChatClientAndServer.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.network; + + +/** + * Combines the server instance and a client instance into the + * same JVM to show an example of, and to test, a pattern like + * self-hosted multiplayer games. + * + * @author Paul Speed + */ +public class TestChatClientAndServer { + + public static void main( String... args ) throws Exception { + + System.out.println("Starting chat server..."); + TestChatServer chatServer = new TestChatServer(); + chatServer.start(); + + System.out.println("Waiting for connections on port:" + TestChatServer.PORT); + + // Now launch a client + + TestChatClient test = new TestChatClient("localhost"); + test.setVisible(true); + + // Register a shutdown hook to get a message on the console when the + // app actually finishes + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + System.out.println("Client and server test is terminating."); + } + }); + + // Keep running basically forever or until the server + // shuts down + while( chatServer.isRunning() ) { + synchronized (chatServer) { + chatServer.wait(); + } + } + } +} diff --git a/JmeTests/src/jme3test/network/TestChatServer.java b/JmeTests/src/jme3test/network/TestChatServer.java new file mode 100644 index 0000000..8bdb740 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestChatServer.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2011 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.network; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.jme3.network.*; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import java.io.IOException; + +/** + * A simple test chat server. When SM implements a set + * of standard chat classes this can become a lot simpler. + * + * @version $Revision$ + * @author Paul Speed + */ +public class TestChatServer { + // Normally these and the initialized method would + // be in shared constants or something. + + public static final String NAME = "Test Chat Server"; + public static final int VERSION = 1; + public static final int PORT = 5110; + public static final int UDP_PORT = 5110; + + private Server server; + private boolean isRunning; + + public TestChatServer() throws IOException { + + // Use this to test the client/server name version check + this.server = Network.createServer(NAME, VERSION, PORT, UDP_PORT); + + // Initialize our own messages only after the server has been created. + // It registers some additional messages with the serializer by default + // that need to go before custom messages. + initializeClasses(); + + ChatHandler handler = new ChatHandler(); + server.addMessageListener(handler, ChatMessage.class); + + server.addConnectionListener(new ChatConnectionListener()); + } + + public boolean isRunning() { + return isRunning; + } + + public synchronized void start() { + if( isRunning ) { + return; + } + server.start(); + isRunning = true; + } + + public synchronized void close() { + if( !isRunning ) { + return; + } + + // Gracefully let any connections know that the server is + // going down. Without this, their connections will simply + // error out. + for( HostedConnection conn : server.getConnections() ) { + conn.close("Server is shutting down."); + } + try { + Thread.sleep(1000); // wait a couple beats to let the messages go out + } catch( InterruptedException e ) { + e.printStackTrace(); + } + + server.close(); + isRunning = false; + notifyAll(); + } + + protected void runCommand( HostedConnection conn, String user, String command ) { + if( "/shutdown".equals(command) ) { + server.broadcast(new ChatMessage("server", "Server is shutting down.")); + close(); + } else if( "/help".equals(command) ) { + StringBuilder sb = new StringBuilder(); + sb.append("Chat commands:\n"); + sb.append("/help - prints this message.\n"); + sb.append("/shutdown - shuts down the server."); + server.broadcast(new ChatMessage("server", sb.toString())); + } + } + + public static void initializeClasses() { + // Doing it here means that the client code only needs to + // call our initialize. + Serializer.registerClass(ChatMessage.class); + } + + public static void main(String... args) throws Exception { + + // Increate the logging level for networking... + System.out.println("Setting logging to max"); + Logger networkLog = Logger.getLogger("com.jme3.network"); + networkLog.setLevel(Level.FINEST); + + // And we have to tell JUL's handler also + // turn up logging in a very convoluted way + Logger rootLog = Logger.getLogger(""); + if( rootLog.getHandlers().length > 0 ) { + rootLog.getHandlers()[0].setLevel(Level.FINEST); + } + + TestChatServer chatServer = new TestChatServer(); + chatServer.start(); + + System.out.println("Waiting for connections on port:" + PORT); + + // Keep running basically forever + while( chatServer.isRunning ) { + synchronized (chatServer) { + chatServer.wait(); + } + } + } + + private class ChatHandler implements MessageListener { + + public ChatHandler() { + } + + @Override + public void messageReceived(HostedConnection source, Message m) { + if (m instanceof ChatMessage) { + // Keep track of the name just in case we + // want to know it for some other reason later and it's + // a good example of session data + ChatMessage cm = (ChatMessage)m; + source.setAttribute("name", cm.getName()); + + // Check for a / command + if( cm.message.startsWith("/") ) { + runCommand(source, cm.name, cm.message); + return; + } + + System.out.println("Broadcasting:" + m + " reliable:" + m.isReliable()); + + // Just rebroadcast... the reliable flag will stay the + // same so if it came in on UDP it will go out on that too + source.getServer().broadcast(cm); + } else { + System.err.println("Received odd message:" + m); + } + } + } + + private class ChatConnectionListener implements ConnectionListener { + + @Override + public void connectionAdded( Server server, HostedConnection conn ) { + System.out.println("connectionAdded(" + conn + ")"); + } + + @Override + public void connectionRemoved(Server server, HostedConnection conn) { + System.out.println("connectionRemoved(" + conn + ")"); + } + + } + + @Serializable + public static class ChatMessage extends AbstractMessage { + + private String name; + private String message; + + public ChatMessage() { + } + + public ChatMessage(String name, String message) { + setName(name); + setMessage(message); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setMessage(String s) { + this.message = s; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return name + ":" + message; + } + } +} diff --git a/JmeTests/src/jme3test/network/TestLatency.java b/JmeTests/src/jme3test/network/TestLatency.java new file mode 100644 index 0000000..c47ae05 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestLatency.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +import com.jme3.network.*; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import java.io.IOException; + +public class TestLatency { + + private static long startTime; + private static Client client; + private static MovingAverage average = new MovingAverage(100); + + static { + startTime = System.currentTimeMillis(); + } + + private static long getTime(){ + return System.currentTimeMillis() - startTime; + } + + @Serializable + public static class TimestampMessage extends AbstractMessage { + + long timeSent = 0; + long timeReceived = 0; + + public TimestampMessage(){ + setReliable(false); + } + + public TimestampMessage(long timeSent, long timeReceived){ + setReliable(false); + this.timeSent = timeSent; + this.timeReceived = timeReceived; + } + + } + + public static void main(String[] args) throws IOException, InterruptedException{ + Serializer.registerClass(TimestampMessage.class); + + Server server = Network.createServer(5110); + server.start(); + + client = Network.connectToServer("localhost", 5110); + client.start(); + + client.addMessageListener(new MessageListener(){ + public void messageReceived(Client source, Message m) { + TimestampMessage timeMsg = (TimestampMessage) m; + + long curTime = getTime(); + //System.out.println("Time sent: " + timeMsg.timeSent); + //System.out.println("Time received by server: " + timeMsg.timeReceived); + //System.out.println("Time received by client: " + curTime); + + long latency = (curTime - timeMsg.timeSent); + System.out.println("Latency: " + (latency) + " ms"); + //long timeOffset = ((timeMsg.timeSent + curTime) / 2) - timeMsg.timeReceived; + //System.out.println("Approximate timeoffset: "+ (timeOffset) + " ms"); + + average.add(latency); + System.out.println("Average latency: " + average.getAverage()); + + long latencyOffset = latency - average.getAverage(); + System.out.println("Latency offset: " + latencyOffset); + + client.send(new TimestampMessage(getTime(), 0)); + } + }, TimestampMessage.class); + + server.addMessageListener(new MessageListener(){ + public void messageReceived(HostedConnection source, Message m) { + TimestampMessage timeMsg = (TimestampMessage) m; + TimestampMessage outMsg = new TimestampMessage(timeMsg.timeSent, getTime()); + source.send(outMsg); + } + }, TimestampMessage.class); + + Thread.sleep(1); + + client.send(new TimestampMessage(getTime(), 0)); + + Object obj = new Object(); + synchronized(obj){ + obj.wait(); + } + } + +} diff --git a/JmeTests/src/jme3test/network/TestMessages.java b/JmeTests/src/jme3test/network/TestMessages.java new file mode 100644 index 0000000..361f097 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestMessages.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +import com.jme3.network.*; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import java.io.IOException; + +public class TestMessages { + + @Serializable + public static class PingMessage extends AbstractMessage { + } + + @Serializable + public static class PongMessage extends AbstractMessage { + } + + private static class ServerPingResponder implements MessageListener { + public void messageReceived(HostedConnection source, com.jme3.network.Message message) { + if (message instanceof PingMessage){ + System.out.println("Server: Received ping message!"); + source.send(new PongMessage()); + } + } + } + + private static class ClientPingResponder implements MessageListener { + public void messageReceived(Client source, com.jme3.network.Message message) { + if (message instanceof PongMessage){ + System.out.println("Client: Received pong message!"); + } + } + } + + public static void main(String[] args) throws IOException, InterruptedException{ + Serializer.registerClass(PingMessage.class); + Serializer.registerClass(PongMessage.class); + + Server server = Network.createServer(5110); + server.start(); + + Client client = Network.connectToServer("localhost", 5110); + client.start(); + + server.addMessageListener(new ServerPingResponder(), PingMessage.class); + client.addMessageListener(new ClientPingResponder(), PongMessage.class); + + System.out.println("Client: Sending ping message.."); + client.send(new PingMessage()); + + Object obj = new Object(); + synchronized (obj){ + obj.wait(); + } + } +} diff --git a/JmeTests/src/jme3test/network/TestNetworkStress.java b/JmeTests/src/jme3test/network/TestNetworkStress.java new file mode 100644 index 0000000..dab33c5 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestNetworkStress.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +import com.jme3.network.*; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestNetworkStress implements ConnectionListener { + + public void connectionAdded(Server server, HostedConnection conn) { + System.out.println("Client Connected: "+conn.getId()); + //conn.close("goodbye"); + } + + public void connectionRemoved(Server server, HostedConnection conn) { + } + + public static void main(String[] args) throws IOException, InterruptedException{ + Logger.getLogger("").getHandlers()[0].setLevel(Level.OFF); + + Server server = Network.createServer(5110); + server.start(); + server.addConnectionListener(new TestNetworkStress()); + + for (int i = 0; i < 1000; i++){ + Client client = Network.connectToServer("localhost", 5110); + client.start(); + + Thread.sleep(10); + + client.close(); + } + } +} diff --git a/JmeTests/src/jme3test/network/TestRemoteCall.java b/JmeTests/src/jme3test/network/TestRemoteCall.java new file mode 100644 index 0000000..4335bb3 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestRemoteCall.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +import com.jme3.app.SimpleApplication; +import com.jme3.export.Savable; +import com.jme3.network.Client; +import com.jme3.network.Network; +import com.jme3.network.Server; +import com.jme3.network.rmi.ObjectStore; +import com.jme3.network.serializing.Serializer; +import com.jme3.network.serializing.serializers.SavableSerializer; +import com.jme3.scene.Spatial; +import java.io.IOException; +import java.util.concurrent.Callable; + +public class TestRemoteCall { + + private static SimpleApplication serverApp; + + /** + * Interface implemented by the server, exposing + * RMI calls that clients can use. + */ + public static interface ServerAccess { + /** + * Attaches the model with the given name to the server's scene. + * + * @param model The model name + * + * @return True if the model was attached. + * + * @throws RuntimeException If some error occurs. + */ + public boolean attachChild(String model); + } + + public static class ServerAccessImpl implements ServerAccess { + public boolean attachChild(String model) { + if (model == null) + throw new RuntimeException("Cannot be null. .. etc"); + + final String finalModel = model; + serverApp.enqueue(new Callable() { + public Void call() throws Exception { + Spatial spatial = serverApp.getAssetManager().loadModel(finalModel); + serverApp.getRootNode().attachChild(spatial); + return null; + } + }); + return true; + } + } + + public static void createServer(){ + serverApp = new SimpleApplication() { + @Override + public void simpleInitApp() { + } + }; + serverApp.start(); + + try { + Server server = Network.createServer(5110); + server.start(); + + ObjectStore store = new ObjectStore(server); + store.exposeObject("access", new ServerAccessImpl()); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + public static void main(String[] args) throws IOException, InterruptedException{ + Serializer.registerClass(Savable.class, new SavableSerializer()); + + createServer(); + + Client client = Network.connectToServer("localhost", 5110); + client.start(); + + ObjectStore store = new ObjectStore(client); + ServerAccess access = store.getExposedObject("access", ServerAccess.class, true); + boolean result = access.attachChild("Models/Oto/Oto.mesh.xml"); + System.out.println(result); + } +} diff --git a/JmeTests/src/jme3test/network/TestSerialization.java b/JmeTests/src/jme3test/network/TestSerialization.java new file mode 100644 index 0000000..cbdeb66 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestSerialization.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.network; + +import com.jme3.network.*; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import java.io.IOException; +import java.util.*; + +public class TestSerialization implements MessageListener { + + @Serializable + public static class SomeObject { + + private int val; + + public SomeObject(){ + } + + public SomeObject(int val){ + this.val = val; + } + + public int getVal(){ + return val; + } + + @Override + public String toString(){ + return "SomeObject[val="+val+"]"; + } + } + + public enum Status { + High, + Middle, + Low; + } + + @Serializable + public static class TestSerializationMessage extends AbstractMessage { + + boolean z; + byte b; + char c; + short s; + int i; + float f; + long l; + double d; + + int[] ia; + List ls; + Map mp; + + Status status1; + Status status2; + + Date date; + + public TestSerializationMessage(){ + super(true); + } + + public TestSerializationMessage(boolean initIt){ + super(true); + if (initIt){ + z = true; + b = -88; + c = 'Y'; + s = 9999; + i = 123; + f = -75.4e8f; + l = 9438345072805034L; + d = -854834.914703e88; + ia = new int[]{ 456, 678, 999 }; + + ls = new ArrayList(); + ls.add("hello"); + ls.add(new SomeObject(-22)); + + mp = new HashMap(); + mp.put("abc", new SomeObject(555)); + + status1 = Status.High; + status2 = Status.Middle; + + date = new Date(System.currentTimeMillis()); + } + } + } + + public void messageReceived(HostedConnection source, Message m) { + TestSerializationMessage cm = (TestSerializationMessage) m; + System.out.println(cm.z); + System.out.println(cm.b); + System.out.println(cm.c); + System.out.println(cm.s); + System.out.println(cm.i); + System.out.println(cm.f); + System.out.println(cm.l); + System.out.println(cm.d); + System.out.println(Arrays.toString(cm.ia)); + System.out.println(cm.ls); + System.out.println(cm.mp); + System.out.println(cm.status1); + System.out.println(cm.status2); + System.out.println(cm.date); + } + + public static void main(String[] args) throws IOException, InterruptedException{ + Serializer.registerClass(SomeObject.class); + Serializer.registerClass(TestSerializationMessage.class); + + Server server = Network.createServer( 5110 ); + server.start(); + + Client client = Network.connectToServer( "localhost", 5110 ); + client.start(); + + server.addMessageListener(new TestSerialization(), TestSerializationMessage.class); + client.send(new TestSerializationMessage(true)); + + Thread.sleep(10000); + } + +} diff --git a/JmeTests/src/jme3test/network/TestThroughput.java b/JmeTests/src/jme3test/network/TestThroughput.java new file mode 100644 index 0000000..c261ec0 --- /dev/null +++ b/JmeTests/src/jme3test/network/TestThroughput.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2011 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.network; + +import com.jme3.network.*; +import com.jme3.network.serializing.Serializable; +import com.jme3.network.serializing.Serializer; +import java.io.IOException; + +public class TestThroughput implements MessageListener { //extends MessageAdapter { + + private static long lastTime = -1; + private static long counter = 0; + private static long total = 0; + // Change this flag to test UDP instead of TCP + private static boolean testReliable = false; + private boolean isOnServer; + + public TestThroughput(boolean isOnServer) { + this.isOnServer = isOnServer; + } + + @Serializable + public static class TestMessage extends AbstractMessage { + + public TestMessage() { + setReliable(testReliable); + } + } + + @Override + public void messageReceived(MessageConnection source, Message msg) { + + if (!isOnServer) { + // It's local to the client so we got it back + counter++; + total++; + long time = System.currentTimeMillis(); +//System.out.println( "total:" + total + " counter:" + counter + " lastTime:" + lastTime + " time:" + time ); + if (lastTime < 0) { + lastTime = time; + } else if (time - lastTime > 1000) { + long delta = time - lastTime; + double scale = delta / 1000.0; + double pps = counter / scale; + System.out.println("messages per second:" + pps + " total messages:" + total); + counter = 0; + lastTime = time; + } + } else { + if (source == null) { + System.out.println("Received a message from a not fully connected source, msg:" + msg); + } else { +//System.out.println( "sending:" + msg + " back to client:" + source ); + // The 'reliable' flag is transient and the server doesn't + // (yet) reset this value for us. + ((com.jme3.network.Message) msg).setReliable(testReliable); + source.send(msg); + } + } + } + + public static void main(String[] args) throws IOException, InterruptedException { + + Serializer.registerClass(TestMessage.class); + + // Use this to test the client/server name version check + //Server server = Network.createServer( "bad name", 42, 5110, 5110 ); + Server server = Network.createServer(5110, 5110); + server.start(); + + Client client = Network.connectToServer("localhost", 5110); + client.start(); + + client.addMessageListener(new TestThroughput(false), TestMessage.class); + server.addMessageListener(new TestThroughput(true), TestMessage.class); + + Thread.sleep(1); + + TestMessage test = new TestMessage(); +// for( int i = 0; i < 10; i++ ) { + while (true) { +//System.out.println( "sending." ); + client.send(test); + } + + //Thread.sleep(5000); + } +} diff --git a/JmeTests/src/jme3test/niftygui/TestNiftyExamples.java b/JmeTests/src/jme3test/niftygui/TestNiftyExamples.java new file mode 100644 index 0000000..19246e4 --- /dev/null +++ b/JmeTests/src/jme3test/niftygui/TestNiftyExamples.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.niftygui; + +import com.jme3.app.SimpleApplication; +import com.jme3.niftygui.NiftyJmeDisplay; +import de.lessvoid.nifty.Nifty; + +public class TestNiftyExamples extends SimpleApplication { + + private Nifty nifty; + + public static void main(String[] args){ + TestNiftyExamples app = new TestNiftyExamples(); + app.setPauseOnLostFocus(false); + app.start(); + } + + public void simpleInitApp() { + NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, + inputManager, + audioRenderer, + guiViewPort); + nifty = niftyDisplay.getNifty(); + + nifty.fromXml("all/intro.xml", "start"); + + // attach the nifty display to the gui view port as a processor + guiViewPort.addProcessor(niftyDisplay); + + // disable the fly cam + flyCam.setEnabled(false); + } + +} diff --git a/JmeTests/src/jme3test/niftygui/TestNiftyGui.java b/JmeTests/src/jme3test/niftygui/TestNiftyGui.java new file mode 100644 index 0000000..3d2e67b --- /dev/null +++ b/JmeTests/src/jme3test/niftygui/TestNiftyGui.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.niftygui; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.niftygui.NiftyJmeDisplay; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import de.lessvoid.nifty.Nifty; +import de.lessvoid.nifty.screen.Screen; +import de.lessvoid.nifty.screen.ScreenController; + +public class TestNiftyGui extends SimpleApplication implements ScreenController { + + private Nifty nifty; + + public static void main(String[] args){ + TestNiftyGui app = new TestNiftyGui(); + app.setPauseOnLostFocus(false); + app.start(); + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( + assetManager, + inputManager, + audioRenderer, + guiViewPort); + nifty = niftyDisplay.getNifty(); + nifty.fromXml("Interface/Nifty/HelloJme.xml", "start", this); + + // attach the nifty display to the gui view port as a processor + guiViewPort.addProcessor(niftyDisplay); + + // disable the fly cam +// flyCam.setEnabled(false); +// flyCam.setDragToRotate(true); + inputManager.setCursorVisible(true); + } + + @Override + public void bind(Nifty nifty, Screen screen) { + System.out.println("bind( " + screen.getScreenId() + ")"); + } + + @Override + public void onStartScreen() { + System.out.println("onStartScreen"); + } + + @Override + public void onEndScreen() { + System.out.println("onEndScreen"); + } + + public void quit(){ + nifty.gotoScreen("end"); + } + +} diff --git a/JmeTests/src/jme3test/niftygui/TestNiftyToMesh.java b/JmeTests/src/jme3test/niftygui/TestNiftyToMesh.java new file mode 100644 index 0000000..ce3832c --- /dev/null +++ b/JmeTests/src/jme3test/niftygui/TestNiftyToMesh.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.niftygui; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.niftygui.NiftyJmeDisplay; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture.MagFilter; +import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.Texture2D; +import de.lessvoid.nifty.Nifty; + +public class TestNiftyToMesh extends SimpleApplication{ + + private Nifty nifty; + + public static void main(String[] args){ + TestNiftyToMesh app = new TestNiftyToMesh(); + app.start(); + } + + public void simpleInitApp() { + ViewPort niftyView = renderManager.createPreView("NiftyView", new Camera(1024, 768)); + niftyView.setClearFlags(true, true, true); + NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, + inputManager, + audioRenderer, + niftyView); + nifty = niftyDisplay.getNifty(); + nifty.fromXml("all/intro.xml", "start"); + niftyView.addProcessor(niftyDisplay); + + Texture2D depthTex = new Texture2D(1024, 768, Format.Depth); + FrameBuffer fb = new FrameBuffer(1024, 768, 1); + fb.setDepthTexture(depthTex); + + Texture2D tex = new Texture2D(1024, 768, Format.RGBA8); + tex.setMinFilter(MinFilter.Trilinear); + tex.setMagFilter(MagFilter.Bilinear); + + fb.setColorTexture(tex); + niftyView.setClearFlags(true, true, true); + niftyView.setOutputFrameBuffer(fb); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", tex); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } +} diff --git a/JmeTests/src/jme3test/opencl/Blas.cl b/JmeTests/src/jme3test/opencl/Blas.cl new file mode 100644 index 0000000..a395692 --- /dev/null +++ b/JmeTests/src/jme3test/opencl/Blas.cl @@ -0,0 +1,4 @@ +__kernel void Fill (__global TYPE* data, TYPE a) +{ + data[get_global_id(0)] = a; +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/opencl/ContextSwitchingScreen.xml b/JmeTests/src/jme3test/opencl/ContextSwitchingScreen.xml new file mode 100644 index 0000000..6f57e96 --- /dev/null +++ b/JmeTests/src/jme3test/opencl/ContextSwitchingScreen.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JmeTests/src/jme3test/opencl/HelloOpenCL.java b/JmeTests/src/jme3test/opencl/HelloOpenCL.java new file mode 100644 index 0000000..e088027 --- /dev/null +++ b/JmeTests/src/jme3test/opencl/HelloOpenCL.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.opencl; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.math.ColorRGBA; +import com.jme3.opencl.*; +import com.jme3.system.AppSettings; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Arrays; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Simple test checking if the basic functions of the OpenCL wrapper work + * @author shaman + */ +public class HelloOpenCL extends SimpleApplication { + private static final Logger LOG = Logger.getLogger(HelloOpenCL.class.getName()); + + public static void main(String[] args){ + HelloOpenCL app = new HelloOpenCL(); + AppSettings settings = new AppSettings(true); + settings.setOpenCLSupport(true); + settings.setVSync(true); +// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE); + app.setSettings(settings); + app.start(); // start the game + } + + @Override + public void simpleInitApp() { + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + Context clContext = context.getOpenCLContext(); + if (clContext == null) { + BitmapText txt = new BitmapText(fnt); + txt.setText("No OpenCL Context created!\nSee output log for details."); + txt.setLocalTranslation(5, settings.getHeight() - 5, 0); + guiNode.attachChild(txt); + return; + } + CommandQueue clQueue = clContext.createQueue(); + + StringBuilder str = new StringBuilder(); + str.append("OpenCL Context created:\n Platform: ") + .append(clContext.getDevices().get(0).getPlatform().getName()) + .append("\n Devices: ").append(clContext.getDevices()); + str.append("\nTests:"); + str.append("\n Buffers: ").append(testBuffer(clContext, clQueue)); + str.append("\n Kernel: ").append(testKernel(clContext, clQueue)); + str.append("\n Images: ").append(testImages(clContext, clQueue)); + + clQueue.release(); + + BitmapText txt1 = new BitmapText(fnt); + txt1.setText(str.toString()); + txt1.setLocalTranslation(5, settings.getHeight() - 5, 0); + guiNode.attachChild(txt1); + + flyCam.setEnabled(false); + inputManager.setCursorVisible(true); + } + + private static void assertEquals(byte expected, byte actual, String message) { + if (expected != actual) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(long expected, long actual, String message) { + if (expected != actual) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(double expected, double actual, String message) { + if (Math.abs(expected - actual) >= 0.00001) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(Object expected, Object actual, String message) { + if (!Objects.equals(expected, actual)) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + + private boolean testBuffer(Context clContext, CommandQueue clQueue) { + try { + //create two buffers + ByteBuffer h1 = BufferUtils.createByteBuffer(256); + Buffer b1 = clContext.createBuffer(256); + ByteBuffer h2 = BufferUtils.createByteBuffer(256); + Buffer b2 = clContext.createBuffer(256); + + //fill buffer + h2.rewind(); + for (int i=0; i<256; ++i) { + h2.put((byte)i); + } + h2.rewind(); + b2.write(clQueue, h2); + + //copy b2 to b1 + b2.copyTo(clQueue, b1); + + //read buffer + h1.rewind(); + b1.read(clQueue, h1); + h1.rewind(); + for (int i=0; i<256; ++i) { + byte b = h1.get(); + assertEquals((byte) i, b, "Wrong byte read"); + } + + //read buffer with offset + int low = 26; + int high = 184; + h1.position(5); + Event event = b1.readAsync(clQueue, h1, high-low, low); + event.waitForFinished(); + h1.position(5); + for (int i=0; i 0){ + return atan(a.y / a.x); + + }else if(a.x < 0 && a.y >= 0){ + return atan(a.y / a.x) + M_PI_F; + + }else if(a.x < 0 && a.y < 0){ + return atan(a.y / a.x) - M_PI_F; + + }else if(a.x == 0 && a.y > 0){ + return M_PI_F/2; + + }else if(a.x == 0 && a.y < 0){ + return -M_PI_F/2; + + }else{ + return 0; + } +} + +inline cfloat cmult(cfloat a, cfloat b){ + return (cfloat)( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); +} + +inline cfloat csqrt(cfloat a){ + return (cfloat)( sqrt(cmod(a)) * cos(carg(a)/2), sqrt(cmod(a)) * sin(carg(a)/2)); +} + +inline float4 getColor(int iteration, int numIterations) { + //color transition: black -> red -> blue -> white + int step = numIterations / 2; + if (iteration < step) { + return mix( (float4)(0,0,0,1), (float4)(1,0,0,1), iteration / (float) step); + } else { + return mix( (float4)(1,0,0,1), (float4)(0,0,1,1), (iteration-step) / (float) (numIterations - step)); + } +} + +__kernel void JuliaSet(write_only image2d_t outputImage, const cfloat C, int numIterations) +{ + // get id of element in array + int x = get_global_id(0); + int y = get_global_id(1); + int w = get_global_size(0); + int h = get_global_size(1); + + cfloat Z = { ( -w / 2 + x) / (w/4.0f) , ( -h / 2 + y) / (h/4.0f) }; + int iteration = 0; + + while (iteration < numIterations) + { + cfloat Zpow2 = cmult(Z, Z); + cfloat Zn = cadd(Zpow2, C); + Z.x = Zn.x; + Z.y = Zn.y; + iteration++; + if(cmod(Z) > 2) + { + break; + } + } + + float4 color; + + // threshold reached mark pixel as white + if (iteration == numIterations) + { + color = (float4)(1,1,1,1); + } + else + { + color = getColor(iteration, numIterations); + } + + write_imagef(outputImage, (int2)(x, y), color); +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/opencl/TestContextSwitching.java b/JmeTests/src/jme3test/opencl/TestContextSwitching.java new file mode 100644 index 0000000..a1d8789 --- /dev/null +++ b/JmeTests/src/jme3test/opencl/TestContextSwitching.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.opencl; + +import com.jme3.app.SimpleApplication; +import com.jme3.niftygui.NiftyJmeDisplay; +import com.jme3.opencl.*; +import com.jme3.system.AppSettings; +import de.lessvoid.nifty.Nifty; +import de.lessvoid.nifty.NiftyEventSubscriber; +import de.lessvoid.nifty.controls.*; +import de.lessvoid.nifty.screen.Screen; +import de.lessvoid.nifty.screen.ScreenController; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Sebastian Weiss + */ +public class TestContextSwitching extends SimpleApplication implements ScreenController { + private static final Logger LOG = Logger.getLogger(TestContextSwitching.class.getName()); + + private Nifty nifty; + private Label infoLabel; + private Button applyButton; + private ListBox platformListBox; + private ListBox deviceListBox; + + private static String selectedPlatform; + private static String selectedDevice; + private Context clContext; + private static List availabePlatforms; + private Buffer testBuffer; + private boolean bufferCreated; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + new TestContextSwitching().start(); + } + + public TestContextSwitching() { + AppSettings settings = new AppSettings(true); + settings.setOpenCLSupport(true); + settings.setVSync(true); + settings.setWidth(800); + settings.setHeight(600); + settings.setOpenCLPlatformChooser(CustomPlatformChooser.class); + //settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE); + + setSettings(settings); + setShowSettings(false); + } + + @Override + public void simpleInitApp() { + + clContext = null; + + NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( + assetManager, + inputManager, + audioRenderer, + guiViewPort); + nifty = niftyDisplay.getNifty(); + nifty.fromXml("jme3test/opencl/ContextSwitchingScreen.xml", "Screen", this); + guiViewPort.addProcessor(niftyDisplay); + inputManager.setCursorVisible(true); + flyCam.setEnabled(false); + } + + @Override + public void simpleUpdate(float tpf) { + if (applyButton != null) { + updateInfos(); + } + } + + @Override + @SuppressWarnings("unchecked") + public void bind(Nifty nifty, Screen screen) { + applyButton = screen.findNiftyControl("ApplyButton", Button.class); + platformListBox = screen.findNiftyControl("PlatformListBox", ListBox.class); + deviceListBox = screen.findNiftyControl("DeviceListBox", ListBox.class); + infoLabel = screen.findNiftyControl("InfoLabel", Label.class); + + updateInfos(); + + platformListBox.clear(); + for (Platform p : availabePlatforms) { + platformListBox.addItem(p.getName()); + } + platformListBox.selectItem(selectedPlatform); + changePlatform(selectedPlatform); + } + + private void updateInfos() { + + if (testBuffer == null && clContext != null && !bufferCreated) { + try { + testBuffer = clContext.createBuffer(1024).register(); + LOG.info("Test buffer created"); + } catch (OpenCLException ex) { + LOG.log(Level.SEVERE, "Unable to create buffer", ex); + } + bufferCreated = true; + } + + Context c = context.getOpenCLContext(); + if (c == clContext) { + return; + } + clContext = c; + LOG.info("context changed"); + testBuffer = null; + bufferCreated = false; + StringBuilder text = new StringBuilder(); + text.append("Current context:\n"); + text.append(" Platform: ").append(clContext.getDevices().get(0).getPlatform().getName()).append("\n"); + text.append(" Device: ").append(clContext.getDevices().get(0).getName()).append("\n"); + text.append(" Profile: ").append(clContext.getDevices().get(0).getProfile()).append("\n"); + text.append(" Memory: ").append(clContext.getDevices().get(0).getGlobalMemorySize()).append(" B\n"); + text.append(" Compute Units: ").append(clContext.getDevices().get(0).getComputeUnits()).append("\n"); + infoLabel.setText(text.toString()); + } + + @NiftyEventSubscriber(id="ApplyButton") + public void onButton(String id, ButtonClickedEvent event) { + LOG.log(Level.INFO, "Change context: platorm={0}, device={1}", new Object[]{selectedPlatform, selectedDevice}); + restart(); + } + + private void changePlatform(String platform) { + selectedPlatform = platform; + Platform p = null; + for (Platform p2 : availabePlatforms) { + if (p2.getName().equals(selectedPlatform)) { + p = p2; + break; + } + } + deviceListBox.clear(); + if (p == null) { + return; + } + for (Device d : p.getDevices()) { + deviceListBox.addItem(d.getName()); + } + deviceListBox.selectItem(selectedDevice); + } + + @NiftyEventSubscriber(id="PlatformListBox") + public void onPlatformChanged(String id, ListBoxSelectionChangedEvent event) { + String p = event.getSelection().isEmpty() ? null : event.getSelection().get(0); + LOG.log(Level.INFO, "Selected platform changed to {0}", p); + selectedPlatform = p; + changePlatform(p); + } + + @NiftyEventSubscriber(id="DeviceListBox") + public void onDeviceChanged(String id, ListBoxSelectionChangedEvent event) { + String d = event.getSelection().isEmpty() ? null : event.getSelection().get(0); + LOG.log(Level.INFO, "Selected device changed to {0}", d); + selectedDevice = d; + } + + @Override + public void onStartScreen() { + + } + + @Override + public void onEndScreen() { + + } + + public static class CustomPlatformChooser implements PlatformChooser { + + public CustomPlatformChooser() {} + + @Override + public List chooseDevices(List platforms) { + availabePlatforms = platforms; + + Platform platform = null; + for (Platform p : platforms) { + if (p.getName().equals(selectedPlatform)) { + platform = p; + break; + } + } + if (platform == null) { + platform = platforms.get(0); + } + selectedPlatform = platform.getName(); + + Device device = null; + for (Device d : platform.getDevices()) { + if (d.getName().equals(selectedDevice)) { + device = d; + break; + } + } + if (device == null) { + for (Device d : platform.getDevices()) { + if (d.getDeviceType() == Device.DeviceType.GPU) { + device = d; + break; + } + } + } + if (device == null) { + device = platform.getDevices().get(0); + } + selectedDevice = device.getName(); + + return Collections.singletonList(device); + } + + } +} diff --git a/JmeTests/src/jme3test/opencl/TestMultipleApplications.java b/JmeTests/src/jme3test/opencl/TestMultipleApplications.java new file mode 100644 index 0000000..1c2a5bf --- /dev/null +++ b/JmeTests/src/jme3test/opencl/TestMultipleApplications.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.opencl; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.font.Rectangle; +import com.jme3.opencl.*; +import com.jme3.system.AppSettings; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class creates multiple instances of {@link TestVertexBufferSharing}. + * This is used to test if multiple opencl instances can run in parallel. + * @author Sebastian Weiss + */ +public class TestMultipleApplications extends SimpleApplication { + private static final Logger LOG = Logger.getLogger(TestMultipleApplications.class.getName()); + + private static final Object sync = new Object(); + private static Platform selectedPlatform; + private static List availableDevices; + private static int currentDeviceIndex; + + private Context clContext; + private CommandQueue clQueue; + private Kernel kernel; + private Buffer buffer; + private boolean failed; + + private BitmapText infoText; + private BitmapText statusText; + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + final AppSettings settings = new AppSettings(true); + settings.setOpenCLSupport(true); + settings.setVSync(true); + settings.setOpenCLPlatformChooser(CustomPlatformChooser.class); + settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE); + for (int i=0; i<2; ++i) { + new Thread() { + public void run() { + if (currentDeviceIndex == -1) { + return; + } + TestMultipleApplications app = new TestMultipleApplications(); + app.setSettings(settings); + app.setShowSettings(false); + app.start(); + } + }.start(); + } + } + + public static class CustomPlatformChooser implements PlatformChooser { + + public CustomPlatformChooser() {} + + @Override + public List chooseDevices(List platforms) { + synchronized(sync) { + if (currentDeviceIndex == -1) { + return Collections.emptyList(); + } + + Platform platform = platforms.get(0); + availableDevices = platform.getDevices(); + selectedPlatform = platform; + + Device device = platform.getDevices().get(currentDeviceIndex); + currentDeviceIndex ++; + if (currentDeviceIndex >= availableDevices.size()) { + currentDeviceIndex = -1; + } + + return Collections.singletonList(device); + } + } + + } + + @Override + public void simpleInitApp() { + clContext = context.getOpenCLContext(); + if (clContext == null) { + LOG.severe("No OpenCL context found"); + stop(); + return; + } + Device device = clContext.getDevices().get(0); + clQueue = clContext.createQueue(device); + clQueue.register(); + + String source = "" + + "__kernel void Fill(__global float* vb, float v)\n" + + "{\n" + + " int idx = get_global_id(0);\n" + + " vb[idx] = v;\n" + + "}\n"; + Program program = clContext.createProgramFromSourceCode(source); + program.build(); + program.register(); + kernel = program.createKernel("Fill"); + kernel.register(); + + buffer = clContext.createBuffer(4); + buffer.register(); + + flyCam.setEnabled(false); + inputManager.setCursorVisible(true); + + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + infoText = new BitmapText(fnt, false); + //infoText.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight())); + infoText.setText("Device: "+clContext.getDevices()); + infoText.setLocalTranslation(0, settings.getHeight(), 0); + guiNode.attachChild(infoText); + statusText = new BitmapText(fnt, false); + //statusText.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight())); + statusText.setText("Running"); + statusText.setLocalTranslation(0, settings.getHeight() - infoText.getHeight() - 2, 0); + guiNode.attachChild(statusText); + } + + @Override + public void simpleUpdate(float tpf) { + //call kernel to test if it is still working + if (!failed) { + try { + kernel.Run1NoEvent(clQueue, new Kernel.WorkSize(1), buffer, 1.0f); + } catch (OpenCLException ex) { + LOG.log(Level.SEVERE, "Kernel call not working anymore", ex); + failed = true; + statusText.setText("Failed"); + } + } + } +} diff --git a/JmeTests/src/jme3test/opencl/TestOpenCLLibraries.java b/JmeTests/src/jme3test/opencl/TestOpenCLLibraries.java new file mode 100644 index 0000000..3964113 --- /dev/null +++ b/JmeTests/src/jme3test/opencl/TestOpenCLLibraries.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.opencl; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Matrix3f; +import com.jme3.math.Matrix4f; +import com.jme3.opencl.*; +import com.jme3.system.AppSettings; +import com.jme3.util.BufferUtils; +import java.nio.*; +import java.util.Arrays; +import java.util.Objects; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Test class for the build in libraries + * @author shaman + */ +public class TestOpenCLLibraries extends SimpleApplication { + private static final Logger LOG = Logger.getLogger(TestOpenCLLibraries.class.getName()); + + public static void main(String[] args){ + TestOpenCLLibraries app = new TestOpenCLLibraries(); + AppSettings settings = new AppSettings(true); + settings.setOpenCLSupport(true); + settings.setVSync(true); +// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE); + app.setSettings(settings); + app.start(); // start the game + } + + @Override + public void simpleInitApp() { + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + Context clContext = context.getOpenCLContext(); + if (clContext == null) { + BitmapText txt = new BitmapText(fnt); + txt.setText("No OpenCL Context created!\nSee output log for details."); + txt.setLocalTranslation(5, settings.getHeight() - 5, 0); + guiNode.attachChild(txt); + return; + } + CommandQueue clQueue = clContext.createQueue(clContext.getDevices().get(0)); + + StringBuilder str = new StringBuilder(); + str.append("OpenCL Context created:\n Platform: ") + .append(clContext.getDevices().get(0).getPlatform().getName()) + .append("\n Devices: ").append(clContext.getDevices()); + str.append("\nTests:"); + str.append("\n Random numbers: ").append(testRandom(clContext, clQueue)); + str.append("\n Matrix3f: ").append(testMatrix3f(clContext, clQueue)); + str.append("\n Matrix4f: ").append(testMatrix4f(clContext, clQueue)); + + clQueue.release(); + + BitmapText txt1 = new BitmapText(fnt); + txt1.setText(str.toString()); + txt1.setLocalTranslation(5, settings.getHeight() - 5, 0); + guiNode.attachChild(txt1); + + flyCam.setEnabled(false); + inputManager.setCursorVisible(true); + } + + private static void assertEquals(byte expected, byte actual, String message) { + if (expected != actual) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(long expected, long actual, String message) { + if (expected != actual) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(double expected, double actual, String message) { + if (Math.abs(expected - actual) >= 0.00001) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + private static void assertEquals(Object expected, Object actual, String message) { + if (!Objects.equals(expected, actual)) { + System.err.println(message+": expected="+expected+", actual="+actual); + throw new AssertionError(); + } + } + + private boolean testRandom(Context clContext, CommandQueue clQueue) { + try { + //test for doubles + boolean supportsDoubles = clContext.getDevices().get(0).hasDouble(); + + //create code + String code = "" + + "#import \"Common/OpenCL/Random.clh\"\n" + + "__kernel void TestBool(__global ulong* seeds, __global uchar* results) {\n" + + " results[get_global_id(0)] = randBool(seeds + get_global_id(0)) ? 1 : 0;\n" + + "}\n" + + "__kernel void TestInt(__global ulong* seeds, __global int* results) {\n" + + " results[get_global_id(0)] = randInt(seeds + get_global_id(0));\n" + + "}\n" + + "__kernel void TestIntN(__global ulong* seeds, int n, __global int* results) {\n" + + " results[get_global_id(0)] = randIntN(n, seeds + get_global_id(0));\n" + + "}\n" + + "__kernel void TestLong(__global ulong* seeds, __global long* results) {\n" + + " results[get_global_id(0)] = randLong(seeds + get_global_id(0));\n" + + "}\n" + + "__kernel void TestFloat(__global ulong* seeds, __global float* results) {\n" + + " results[get_global_id(0)] = randFloat(seeds + get_global_id(0));\n" + + "}\n" + + "#ifdef RANDOM_DOUBLES\n" + + "__kernel void TestDouble(__global ulong* seeds, __global double* results) {\n" + + " results[get_global_id(0)] = randDouble(seeds + get_global_id(0));\n" + + "}\n" + + "#endif\n"; + if (supportsDoubles) { + code = "#define RANDOM_DOUBLES\n" + code; + } + Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager); + program.build(); + + int count = 256; + Kernel.WorkSize ws = new Kernel.WorkSize(count); + + //create seeds + Random initRandom = new Random(); + long[] seeds = new long[count]; + Random[] randoms = new Random[count]; + for (int i=0; i 0 ) { + fpp.setNumSamples(numSamples); + } + + BloomFilter bloom=new BloomFilter(); + bloom.setDownSamplingFactor(2); + bloom.setBlurScale(1.37f); + bloom.setExposurePower(3.30f); + bloom.setExposureCutOff(0.2f); + bloom.setBloomIntensity(2.45f); + BloomUI ui=new BloomUI(inputManager, bloom); + + + viewPort.addProcessor(fpp); + fpp.addFilter(bloom); + initInputs(); + + } + + private void initInputs() { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + if(active){ + active=false; + viewPort.removeProcessor(fpp); + }else{ + active=true; + viewPort.addProcessor(fpp); + } + } + } + }; + + inputManager.addListener(acl, "toggle"); + + } + + + +} diff --git a/JmeTests/src/jme3test/post/TestBloomAlphaThreshold.java b/JmeTests/src/jme3test/post/TestBloomAlphaThreshold.java new file mode 100644 index 0000000..b9f1367 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestBloomAlphaThreshold.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.BloomFilter.GlowMode; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; + +public class TestBloomAlphaThreshold extends SimpleApplication +{ + + float angle; + Spatial lightMdl; + Spatial teapot; + Geometry frustumMdl; + WireFrustum frustum; + boolean active = true; + FilterPostProcessor fpp; + + public static void main(String[] args) + { + TestBloomAlphaThreshold app = new TestBloomAlphaThreshold(); + app.start(); + } + + @Override + public void simpleInitApp() + { + // put the camera in a bad position + cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -10)); + cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); + // cam.setFrustumFar(1000); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + + mat.setFloat("Shininess", 15f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); + mat.setColor("GlowColor", ColorRGBA.Green); + + Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + matSoil.setFloat("Shininess", 15f); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Gray); + + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(0, 0, 10); + + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + teapot.setLocalScale(10.0f); + rootNode.attachChild(teapot); + + Vector3f boxMin1 = new Vector3f(-800f, -23f, -150f); + Vector3f boxMax1 = new Vector3f(800f, 3f, 1250f); + Box boxMesh1 = new Box(boxMin1, boxMax1); + Geometry soil = new Geometry("soil", boxMesh1); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(soil); + + Material matBox = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matBox.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png")); + matBox.setFloat("AlphaDiscardThreshold", 0.5f); + + Vector3f boxMin2 = new Vector3f(-5.5f, 8f, -4f); + Vector3f boxMax2 = new Vector3f(-1.5f, 12f, 0f); + Box boxMesh2 = new Box(boxMin2, boxMax2); + Geometry box = new Geometry("box", boxMesh2); + box.setMaterial(matBox); + box.setQueueBucket(RenderQueue.Bucket.Translucent); + // box.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(box); + + DirectionalLight light = new DirectionalLight(); + light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + + // load sky + Spatial sky = SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/FullskiesBlueClear03.dds", + EnvMapType.CubeMap); + sky.setCullHint(Spatial.CullHint.Never); + rootNode.attachChild(sky); + + fpp = new FilterPostProcessor(assetManager); + int numSamples = getContext().getSettings().getSamples(); + if (numSamples > 0) + { + fpp.setNumSamples(numSamples); + } + + BloomFilter bloom = new BloomFilter(GlowMode.Objects); + bloom.setDownSamplingFactor(2); + bloom.setBlurScale(1.37f); + bloom.setExposurePower(3.30f); + bloom.setExposureCutOff(0.2f); + bloom.setBloomIntensity(2.45f); + BloomUI ui = new BloomUI(inputManager, bloom); + + viewPort.addProcessor(fpp); + fpp.addFilter(bloom); + initInputs(); + + } + + private void initInputs() + { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + ActionListener acl = new ActionListener() + { + + @Override + public void onAction(String name, boolean keyPressed, float tpf) + { + if (name.equals("toggle") && keyPressed) + { + if (active) + { + active = false; + viewPort.removeProcessor(fpp); + } + else + { + active = true; + viewPort.addProcessor(fpp); + } + } + } + }; + + inputManager.addListener(acl, "toggle"); + + } + +} diff --git a/JmeTests/src/jme3test/post/TestCartoonEdge.java b/JmeTests/src/jme3test/post/TestCartoonEdge.java new file mode 100644 index 0000000..ff6ab49 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestCartoonEdge.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.CartoonEdgeFilter; +import com.jme3.renderer.Caps; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.texture.Texture; + +public class TestCartoonEdge extends SimpleApplication { + + private FilterPostProcessor fpp; + + public static void main(String[] args){ + TestCartoonEdge app = new TestCartoonEdge(); + app.start(); + } + + public void setupFilters(){ + if (renderer.getCaps().contains(Caps.GLSL100)){ + fpp=new FilterPostProcessor(assetManager); + //fpp.setNumSamples(4); + int numSamples = getContext().getSettings().getSamples(); + if( numSamples > 0 ) { + fpp.setNumSamples(numSamples); + } + CartoonEdgeFilter toon=new CartoonEdgeFilter(); + toon.setEdgeColor(ColorRGBA.Yellow); + fpp.addFilter(toon); + viewPort.addProcessor(fpp); + } + } + + public void makeToonish(Spatial spatial){ + if (spatial instanceof Node){ + Node n = (Node) spatial; + for (Spatial child : n.getChildren()) + makeToonish(child); + }else if (spatial instanceof Geometry){ + Geometry g = (Geometry) spatial; + Material m = g.getMaterial(); + if (m.getMaterialDef().getMaterialParam("UseMaterialColors") != null) { + Texture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); +// t.setMinFilter(Texture.MinFilter.NearestNoMipMaps); +// t.setMagFilter(Texture.MagFilter.Nearest); + m.setTexture("ColorRamp", t); + m.setBoolean("UseMaterialColors", true); + m.setColor("Specular", ColorRGBA.Black); + m.setColor("Diffuse", ColorRGBA.White); + m.setBoolean("VertexLighting", true); + } + } + } + + public void setupLighting(){ + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, 1).normalizeLocal()); + dl.setColor(new ColorRGBA(2,2,2,1)); + + rootNode.addLight(dl); + } + + public void setupModel(){ + Spatial model = assetManager.loadModel("Models/MonkeyHead/MonkeyHead.mesh.xml"); + makeToonish(model); + model.rotate(0, FastMath.PI, 0); +// signpost.setLocalTranslation(12, 3.5f, 30); +// model.scale(0.10f); +// signpost.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(model); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.Gray); + + cam.setLocation(new Vector3f(-5.6310086f, 5.0892987f, -13.000479f)); + cam.setRotation(new Quaternion(0.1779095f, 0.20036356f, -0.03702727f, 0.96272093f)); + cam.update(); + + cam.setFrustumFar(300); + flyCam.setMoveSpeed(30); + + rootNode.setCullHint(CullHint.Never); + + setupLighting(); + setupModel(); + setupFilters(); + } + +} diff --git a/JmeTests/src/jme3test/post/TestCrossHatch.java b/JmeTests/src/jme3test/post/TestCrossHatch.java new file mode 100644 index 0000000..5cc3669 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestCrossHatch.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.CrossHatchFilter; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; + +public class TestCrossHatch extends SimpleApplication { + + float angle; + Spatial lightMdl; + Spatial teapot; + Geometry frustumMdl; + WireFrustum frustum; + boolean active=true; + FilterPostProcessor fpp; + + public static void main(String[] args){ + TestCrossHatch app = new TestCrossHatch(); + app.start(); + } + + @Override + public void simpleInitApp() { + // put the camera in a bad position + cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -7.139601f)); + cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); + //cam.setFrustumFar(1000); + + + Material mat = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 15f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); + + + + + Material matSoil = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + matSoil.setFloat("Shininess", 15f); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Gray); + + + + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(0,0,10); + + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + teapot.setLocalScale(10.0f); + rootNode.attachChild(teapot); + + + + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(soil); + + DirectionalLight light=new DirectionalLight(); + light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + + // load sky + Spatial sky = SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/FullskiesBlueClear03.dds", + EnvMapType.CubeMap); + sky.setCullHint(Spatial.CullHint.Never); + rootNode.attachChild(sky); + + fpp=new FilterPostProcessor(assetManager); + + int numSamples = getContext().getSettings().getSamples(); + if( numSamples > 0 ) { + fpp.setNumSamples(numSamples); + } + + CrossHatchFilter chf=new CrossHatchFilter(); + + + + viewPort.addProcessor(fpp); + fpp.addFilter(chf); + initInputs(); + + } + + private void initInputs() { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + if(active){ + active=false; + viewPort.removeProcessor(fpp); + }else{ + active=true; + viewPort.addProcessor(fpp); + } + } + } + }; + + inputManager.addListener(acl, "toggle"); + + } + + + +} diff --git a/JmeTests/src/jme3test/post/TestDepthOfField.java b/JmeTests/src/jme3test/post/TestDepthOfField.java new file mode 100644 index 0000000..263d45f --- /dev/null +++ b/JmeTests/src/jme3test/post/TestDepthOfField.java @@ -0,0 +1,206 @@ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.DepthOfFieldFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import java.util.ArrayList; +import java.util.List; + +/** + * test + * @author Nehon + */ +public class TestDepthOfField extends SimpleApplication { + + private FilterPostProcessor fpp; + private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f); + TerrainQuad terrain; + Material matRock; + DepthOfFieldFilter dofFilter; + + public static void main(String[] args) { + TestDepthOfField app = new TestDepthOfField(); + app.start(); + } + + @Override + public void simpleInitApp() { + + + Node mainScene = new Node("Main Scene"); + rootNode.attachChild(mainScene); + + createTerrain(mainScene); + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(1.7f)); + mainScene.addLight(sun); + + DirectionalLight l = new DirectionalLight(); + l.setDirection(Vector3f.UNIT_Y.mult(-1)); + l.setColor(ColorRGBA.White.clone().multLocal(0.3f)); + mainScene.addLight(l); + + flyCam.setMoveSpeed(50); + cam.setFrustumFar(3000); + cam.setLocation(new Vector3f(-700, 100, 300)); + cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0})); + + + Spatial sky = SkyFactory.createSky(assetManager, + "Scenes/Beach/FullskiesSunset0068.dds", EnvMapType.CubeMap); + sky.setLocalScale(350); + mainScene.attachChild(sky); + + + + fpp = new FilterPostProcessor(assetManager); + // fpp.setNumSamples(4); + int numSamples = getContext().getSettings().getSamples(); + if( numSamples > 0 ) { + fpp.setNumSamples(numSamples); + } + + dofFilter = new DepthOfFieldFilter(); + dofFilter.setFocusDistance(0); + dofFilter.setFocusRange(50); + dofFilter.setBlurScale(1.4f); + fpp.addFilter(dofFilter); + viewPort.addProcessor(fpp); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + if (name.equals("toggle")) { + dofFilter.setEnabled(!dofFilter.isEnabled()); + } + + + } + } + }, "toggle"); + inputManager.addListener(new AnalogListener() { + + public void onAnalog(String name, float value, float tpf) { + if (name.equals("blurScaleUp")) { + dofFilter.setBlurScale(dofFilter.getBlurScale() + 0.01f); + System.out.println("blurScale : " + dofFilter.getBlurScale()); + } + if (name.equals("blurScaleDown")) { + dofFilter.setBlurScale(dofFilter.getBlurScale() - 0.01f); + System.out.println("blurScale : " + dofFilter.getBlurScale()); + } + if (name.equals("focusRangeUp")) { + dofFilter.setFocusRange(dofFilter.getFocusRange() + 1f); + System.out.println("focusRange : " + dofFilter.getFocusRange()); + } + if (name.equals("focusRangeDown")) { + dofFilter.setFocusRange(dofFilter.getFocusRange() - 1f); + System.out.println("focusRange : " + dofFilter.getFocusRange()); + } + if (name.equals("focusDistanceUp")) { + dofFilter.setFocusDistance(dofFilter.getFocusDistance() + 1f); + System.out.println("focusDistance : " + dofFilter.getFocusDistance()); + } + if (name.equals("focusDistanceDown")) { + dofFilter.setFocusDistance(dofFilter.getFocusDistance() - 1f); + System.out.println("focusDistance : " + dofFilter.getFocusDistance()); + } + + } + }, "blurScaleUp", "blurScaleDown", "focusRangeUp", "focusRangeDown", "focusDistanceUp", "focusDistanceDown"); + + + inputManager.addMapping("toggle", new KeyTrigger(keyInput.KEY_SPACE)); + inputManager.addMapping("blurScaleUp", new KeyTrigger(keyInput.KEY_U)); + inputManager.addMapping("blurScaleDown", new KeyTrigger(keyInput.KEY_J)); + inputManager.addMapping("focusRangeUp", new KeyTrigger(keyInput.KEY_I)); + inputManager.addMapping("focusRangeDown", new KeyTrigger(keyInput.KEY_K)); + inputManager.addMapping("focusDistanceUp", new KeyTrigger(keyInput.KEY_O)); + inputManager.addMapping("focusDistanceDown", new KeyTrigger(keyInput.KEY_L)); + + } + + private void createTerrain(Node rootNode) { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(5, 5, 5)); + terrain.setLocalTranslation(new Vector3f(0, -30, 0)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(terrain); + + } + + @Override + public void simpleUpdate(float tpf) { + Vector3f origin = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.0f); + Vector3f direction = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.3f); + direction.subtractLocal(origin).normalizeLocal(); + Ray ray = new Ray(origin, direction); + CollisionResults results = new CollisionResults(); + int numCollisions = terrain.collideWith(ray, results); + if (numCollisions > 0) { + CollisionResult hit = results.getClosestCollision(); + fpsText.setText(""+hit.getDistance()); + dofFilter.setFocusDistance(hit.getDistance()/10.0f); + } + } +} diff --git a/JmeTests/src/jme3test/post/TestFBOPassthrough.java b/JmeTests/src/jme3test/post/TestFBOPassthrough.java new file mode 100644 index 0000000..47b74f4 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestFBOPassthrough.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture2D; +import com.jme3.ui.Picture; + +/** + * Demonstrates FrameBuffer usage. + * The scene is first rendered to an FB with a texture attached, + * the texture is then rendered onto the screen in ortho mode. + * + * @author Kirill + */ +public class TestFBOPassthrough extends SimpleApplication { + + private Node fbNode = new Node("Framebuffer Node"); + private FrameBuffer fb; + + public static void main(String[] args){ + TestFBOPassthrough app = new TestFBOPassthrough(); + app.start(); + } + + @Override + public void simpleInitApp() { + int w = settings.getWidth(); + int h = settings.getHeight(); + + //setup framebuffer + fb = new FrameBuffer(w, h, 1); + + Texture2D fbTex = new Texture2D(w, h, Format.RGBA8); + fb.setDepthBuffer(Format.Depth); + fb.setColorTexture(fbTex); + + // setup framebuffer's scene + Sphere sphMesh = new Sphere(20, 20, 1); + Material solidColor = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + + Geometry sphere = new Geometry("sphere", sphMesh); + sphere.setMaterial(solidColor); + fbNode.attachChild(sphere); + + //setup main scene + Picture p = new Picture("Picture"); + p.setPosition(0, 0); + p.setWidth(w); + p.setHeight(h); + p.setTexture(assetManager, fbTex, false); + + rootNode.attachChild(p); + } + + @Override + public void simpleUpdate(float tpf){ + fbNode.updateLogicalState(tpf); + fbNode.updateGeometricState(); + } + + @Override + public void simpleRender(RenderManager rm){ + Renderer r = rm.getRenderer(); + + //do FBO rendering + r.setFrameBuffer(fb); + + rm.setCamera(cam, false); // FBO uses current camera + r.clearBuffers(true, true, true); + rm.renderScene(fbNode, viewPort); + rm.flushQueue(viewPort); + + //go back to default rendering and let + //SimpleApplication render the default scene + r.setFrameBuffer(null); + } + +} diff --git a/JmeTests/src/jme3test/post/TestFog.java b/JmeTests/src/jme3test/post/TestFog.java new file mode 100644 index 0000000..544932a --- /dev/null +++ b/JmeTests/src/jme3test/post/TestFog.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.FogFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.util.SkyFactory; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class TestFog extends SimpleApplication { + + private FilterPostProcessor fpp; + private boolean enabled=true; + private FogFilter fog; + + public static void main(String[] args) { + TestFog app = new TestFog(); + app.start(); + } + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(50); + Node mainScene=new Node(); + cam.setLocation(new Vector3f(-34.74095f, 95.21318f, -287.4945f)); + cam.setRotation(new Quaternion(0.023536969f, 0.9361278f, -0.016098259f, -0.35050195f)); + + // load sky + mainScene.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + createTerrain(mainScene); + + + + DirectionalLight sun = new DirectionalLight(); + Vector3f lightDir=new Vector3f(-0.37352666f, -0.50444174f, -0.7784704f); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + mainScene.addLight(sun); + + rootNode.attachChild(mainScene); + + fpp=new FilterPostProcessor(assetManager); + //fpp.setNumSamples(4); + int numSamples = getContext().getSettings().getSamples(); + if( numSamples > 0 ) { + fpp.setNumSamples(numSamples); + } + fog=new FogFilter(); + fog.setFogColor(new ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f)); + fog.setFogDistance(155); + fog.setFogDensity(1.0f); + fpp.addFilter(fog); + viewPort.addProcessor(fpp); + initInputs(); + } + + private void initInputs() { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("DensityUp", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("DensityDown", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("DistanceUp", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("DistanceDown", new KeyTrigger(KeyInput.KEY_J)); + + + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + if(enabled){ + enabled=false; + viewPort.removeProcessor(fpp); + }else{ + enabled=true; + viewPort.addProcessor(fpp); + } + } + + } + }; + + AnalogListener anl=new AnalogListener() { + + public void onAnalog(String name, float isPressed, float tpf) { + if(name.equals("DensityUp")){ + fog.setFogDensity(fog.getFogDensity()+0.001f); + System.out.println("Fog density : "+fog.getFogDensity()); + } + if(name.equals("DensityDown")){ + fog.setFogDensity(fog.getFogDensity()-0.010f); + System.out.println("Fog density : "+fog.getFogDensity()); + } + if(name.equals("DistanceUp")){ + fog.setFogDistance(fog.getFogDistance()+0.5f); + System.out.println("Fog Distance : "+fog.getFogDistance()); + } + if(name.equals("DistanceDown")){ + fog.setFogDistance(fog.getFogDistance()-0.5f); + System.out.println("Fog Distance : "+fog.getFogDistance()); + } + + } + }; + + inputManager.addListener(acl, "toggle"); + inputManager.addListener(anl, "DensityUp","DensityDown","DistanceUp","DistanceDown"); + + } + + private void createTerrain(Node rootNode) { + Material matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(Texture.WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(Texture.WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(Texture.WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(Texture.WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(Texture.WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(Texture.WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + TerrainQuad terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(5, 5, 5)); + terrain.setLocalTranslation(new Vector3f(0, -30, 0)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(RenderQueue.ShadowMode.Receive); + rootNode.attachChild(terrain); + + } +} + diff --git a/JmeTests/src/jme3test/post/TestLightScattering.java b/JmeTests/src/jme3test/post/TestLightScattering.java new file mode 100644 index 0000000..c2940ca --- /dev/null +++ b/JmeTests/src/jme3test/post/TestLightScattering.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.LightScatteringFilter; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.util.SkyFactory; +import com.jme3.util.TangentBinormalGenerator; + +public class TestLightScattering extends SimpleApplication { + + public static void main(String[] args) { + TestLightScattering app = new TestLightScattering(); + + app.start(); + } + + @Override + public void simpleInitApp() { + // put the camera in a bad position + cam.setLocation(new Vector3f(55.35316f, -0.27061665f, 27.092093f)); + cam.setRotation(new Quaternion(0.010414706f, 0.9874893f, 0.13880467f, -0.07409228f)); +// cam.setDirection(new Vector3f(0,-0.5f,1.0f)); +// cam.setLocation(new Vector3f(0, 300, -500)); + //cam.setFrustumFar(1000); + flyCam.setMoveSpeed(10); + Material mat = assetManager.loadMaterial("Textures/Terrain/Rocky/Rocky.j3m"); + Spatial scene = assetManager.loadModel("Models/Terrain/Terrain.mesh.xml"); + TangentBinormalGenerator.generate(((Geometry)((Node)scene).getChild(0)).getMesh()); + scene.setMaterial(mat); + scene.setShadowMode(ShadowMode.CastAndReceive); + scene.setLocalScale(400); + scene.setLocalTranslation(0, -10, -120); + + rootNode.attachChild(scene); + + // load sky + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/FullskiesBlueClear03.dds", + SkyFactory.EnvMapType.CubeMap)); + + DirectionalLight sun = new DirectionalLight(); + Vector3f lightDir = new Vector3f(-0.12f, -0.3729129f, 0.74847335f); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + scene.addLight(sun); + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + int numSamples = getContext().getSettings().getSamples(); + if (numSamples > 0) { + fpp.setNumSamples(numSamples); + } + Vector3f lightPos = lightDir.multLocal(-3000); + LightScatteringFilter filter = new LightScatteringFilter(lightPos); + LightScatteringUI ui = new LightScatteringUI(inputManager, filter); + fpp.addFilter(filter); + viewPort.addProcessor(fpp); + } + + @Override + public void simpleUpdate(float tpf) { + } +} diff --git a/JmeTests/src/jme3test/post/TestMultiRenderTarget.java b/JmeTests/src/jme3test/post/TestMultiRenderTarget.java new file mode 100644 index 0000000..ccb073a --- /dev/null +++ b/JmeTests/src/jme3test/post/TestMultiRenderTarget.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Matrix4f; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.SceneProcessor; +import com.jme3.profile.AppProfiler; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Node; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture2D; +import com.jme3.ui.Picture; + +public class TestMultiRenderTarget extends SimpleApplication implements SceneProcessor { + + private FrameBuffer fb; + private Texture2D diffuseData, normalData, specularData, depthData; + private Picture display1, display2, display3, display4; + + private Picture display; + private Material mat; + + private String techOrig; + private PointLight[] pls; + + public static void main(String[] args){ + TestMultiRenderTarget app = new TestMultiRenderTarget(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.addProcessor(this); + +// flyCam.setEnabled(false); + cam.setLocation(new Vector3f(4.8037705f, 4.851632f, 10.789033f)); + cam.setRotation(new Quaternion(-0.05143692f, 0.9483723f, -0.21131563f, -0.230846f)); + + Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); + + //tankMesh.getMaterial().setColor("Specular", ColorRGBA.Black); + rootNode.attachChild(tank); + + display1 = new Picture("Picture"); + display1.move(0, 0, -1); // make it appear behind stats view + display2 = (Picture) display1.clone(); + display3 = (Picture) display1.clone(); + display4 = (Picture) display1.clone(); + display = (Picture) display1.clone(); + + ColorRGBA[] colors = new ColorRGBA[]{ + ColorRGBA.White, + ColorRGBA.Blue, + ColorRGBA.Cyan, + ColorRGBA.DarkGray, + ColorRGBA.Green, + ColorRGBA.Magenta, + ColorRGBA.Orange, + ColorRGBA.Pink, + ColorRGBA.Red, + ColorRGBA.Yellow + }; + + pls = new PointLight[3]; + for (int i = 0; i < pls.length; i++){ + PointLight pl = new PointLight(); + pl.setColor(colors[i % colors.length]); + pl.setRadius(5); + display.addLight(pl); + pls[i] = pl; + } + } + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf);//To change body of generated methods, choose Tools | Templates. + for (int i = 0; i < 3; i++){ + PointLight pl = pls[i]; + float angle = (float)Math.PI * (i + (timer.getTimeInSeconds() % 6)/3); // 3s for full loop + pl.setPosition( new Vector3f(FastMath.cos(angle)*3f, 0, + FastMath.sin(angle)*3f)); + } + } + public void initialize(RenderManager rm, ViewPort vp) { + reshape(vp, vp.getCamera().getWidth(), vp.getCamera().getHeight()); + viewPort.setOutputFrameBuffer(fb); + guiViewPort.setClearFlags(true, true, true); + guiNode.attachChild(display); +// guiNode.attachChild(display1); + guiNode.attachChild(display2); +// guiNode.attachChild(display3); +// guiNode.attachChild(display4); + guiNode.updateGeometricState(); + } + + public void reshape(ViewPort vp, int w, int h) { + diffuseData = new Texture2D(w, h, Format.RGBA8); + normalData = new Texture2D(w, h, Format.RGBA8); + specularData = new Texture2D(w, h, Format.RGBA8); + depthData = new Texture2D(w, h, Format.Depth); + + mat = new Material(assetManager, "Common/MatDefs/Light/Deferred.j3md"); + mat.setTexture("DiffuseData", diffuseData); + mat.setTexture("SpecularData", specularData); + mat.setTexture("NormalData", normalData); + mat.setTexture("DepthData", depthData); + + display.setMaterial(mat); + display.setPosition(0, 0); + display.setWidth(w); + display.setHeight(h); + + display1.setTexture(assetManager, diffuseData, false); + display2.setTexture(assetManager, normalData, false); + display3.setTexture(assetManager, specularData, false); + display4.setTexture(assetManager, depthData, false); + + display1.setPosition(0, 0); + display2.setPosition(w/2, 0); + display3.setPosition(0, h/2); + display4.setPosition(w/2, h/2); + + display1.setWidth(w/2); + display1.setHeight(h/2); + + display2.setWidth(w/2); + display2.setHeight(h/2); + + display3.setWidth(w/2); + display3.setHeight(h/2); + + display4.setWidth(w/2); + display4.setHeight(h/2); + + guiNode.updateGeometricState(); + + fb = new FrameBuffer(w, h, 1); + fb.setDepthTexture(depthData); + fb.addColorTexture(diffuseData); + fb.addColorTexture(normalData); + fb.addColorTexture(specularData); + fb.setMultiTarget(true); + + /* + * Marks pixels in front of the far light boundary + Render back-faces of light volume + Depth test GREATER-EQUAL + Write to stencil on depth pass + Skipped for very small distant lights + */ + + /* + * Find amount of lit pixels inside the volume + Start pixel query + Render front faces of light volume + Depth test LESS-EQUAL + Don’t write anything – only EQUAL stencil test + */ + + /* + * Enable conditional rendering + Based on query results from previous stage + GPU skips rendering for invisible lights + */ + + /* + * Render front-faces of light volume + Depth test - LESS-EQUAL + Stencil test - EQUAL + Runs only on marked pixels inside light + */ + } + + public boolean isInitialized() { + return diffuseData != null; + } + + public void preFrame(float tpf) { + Matrix4f inverseViewProj = cam.getViewProjectionMatrix().invert(); + mat.setMatrix4("ViewProjectionMatrixInverse", inverseViewProj); + techOrig = renderManager.getForcedTechnique(); + renderManager.setForcedTechnique("GBuf"); + } + + public void postQueue(RenderQueue rq) { + } + + public void postFrame(FrameBuffer out) { + renderManager.setForcedTechnique(techOrig); + } + + public void cleanup() { + } + + @Override + public void setProfiler(AppProfiler profiler) { + + } + +} diff --git a/JmeTests/src/jme3test/post/TestMultiViewsFilters.java b/JmeTests/src/jme3test/post/TestMultiViewsFilters.java new file mode 100644 index 0000000..adbc036 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestMultiViewsFilters.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.*; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.util.SkyFactory; + +public class TestMultiViewsFilters extends SimpleApplication { + + public static void main(String[] args) { + TestMultiViewsFilters app = new TestMultiViewsFilters(); + app.start(); + } + private boolean filterEnabled = true; + + public void simpleInitApp() { + // create the geometry and attach it + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teaGeom.scale(3); + teaGeom.getMaterial().setColor("GlowColor", ColorRGBA.Green); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + // Setup first view + cam.setViewPort(.5f, 1f, 0f, 0.5f); + cam.setLocation(new Vector3f(3.3212643f, 4.484704f, 4.2812433f)); + cam.setRotation(new Quaternion(-0.07680723f, 0.92299235f, -0.2564353f, -0.27645364f)); + + // Setup second view + Camera cam2 = cam.clone(); + cam2.setViewPort(0f, 0.5f, 0f, 0.5f); + cam2.setLocation(new Vector3f(-0.10947256f, 1.5760219f, 4.81758f)); + cam2.setRotation(new Quaternion(0.0010108891f, 0.99857414f, -0.04928594f, 0.020481428f)); + + final ViewPort view2 = renderManager.createMainView("Bottom Left", cam2); + view2.setClearFlags(true, true, true); + view2.attachScene(rootNode); + + // Setup third view + Camera cam3 = cam.clone(); + cam3.setName("cam3"); + cam3.setViewPort(0f, .5f, .5f, 1f); + cam3.setLocation(new Vector3f(0.2846221f, 6.4271426f, 0.23380789f)); + cam3.setRotation(new Quaternion(0.004381671f, 0.72363687f, -0.69015175f, 0.0045953835f)); + + final ViewPort view3 = renderManager.createMainView("Top Left", cam3); + view3.setClearFlags(true, true, true); + view3.attachScene(rootNode); + + + // Setup fourth view + Camera cam4 = cam.clone(); + cam4.setName("cam4"); + cam4.setViewPort(.5f, 1f, .5f, 1f); + + cam4.setLocation(new Vector3f(4.775564f, 1.4548365f, 0.11491505f)); + cam4.setRotation(new Quaternion(0.02356979f, -0.74957186f, 0.026729556f, 0.66096294f)); + + final ViewPort view4 = renderManager.createMainView("Top Right", cam4); + view4.setClearFlags(true, true, true); + view4.attachScene(rootNode); + +// Camera cam5 = new Camera(200, 200); +// cam5.setFrustumPerspective(45f, (float)cam.getWidth() / cam.getHeight(), 1f, 1000f); +// cam5.setName("cam5"); +// cam5.setViewPort(5.23f, 6.33f, 0.56f, 1.66f); +// this.setViewPortAreas(5.23f, 6.33f, 0.56f, 1.66f); +// this.setViewPortCamSize(200, 200); +// 1046,1266,112,332 + Camera cam5 = cam.clone(); + cam5.setName("cam5"); + cam5.setViewPort(1046f/settings.getWidth(), 1266f/settings.getWidth(), 112f/settings.getHeight(), 332f/settings.getHeight()); + cam5.setLocation(new Vector3f(0.2846221f, 6.4271426f, 0.23380789f)); + cam5.setRotation(new Quaternion(0.004381671f, 0.72363687f, -0.69015175f, 0.0045953835f)); + + final ViewPort view5 = renderManager.createMainView("center", cam5); + view5.setClearFlags(true, true, true); + view5.attachScene(rootNode); + + + + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + + final FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp2 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp3 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp4 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp5 = new FilterPostProcessor(assetManager); + + + // fpp.addFilter(new WaterFilter(rootNode, Vector3f.UNIT_Y.mult(-1))); + fpp3.addFilter(new CartoonEdgeFilter()); + + fpp2.addFilter(new CrossHatchFilter()); + final FogFilter ff = new FogFilter(ColorRGBA.Yellow, 0.7f, 2); + fpp.addFilter(ff); + + final RadialBlurFilter rbf = new RadialBlurFilter(1, 10); + // rbf.setEnabled(false); + fpp.addFilter(rbf); + + + SSAOFilter f = new SSAOFilter(1.8899765f, 20.490374f, 0.4699998f, 0.1f);; + fpp4.addFilter(f); + SSAOUI ui = new SSAOUI(inputManager, f); + + fpp5.addFilter(new BloomFilter(BloomFilter.GlowMode.Objects)); + + viewPort.addProcessor(fpp); + view2.addProcessor(fpp2); + view3.addProcessor(fpp3); + view4.addProcessor(fpp4); + view5.addProcessor(fpp5); + + + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("press") && isPressed) { + if (filterEnabled) { + viewPort.removeProcessor(fpp); + view2.removeProcessor(fpp2); + view3.removeProcessor(fpp3); + view4.removeProcessor(fpp4); + view5.removeProcessor(fpp5); + } else { + viewPort.addProcessor(fpp); + view2.addProcessor(fpp2); + view3.addProcessor(fpp3); + view4.addProcessor(fpp4); + view5.addProcessor(fpp5); + } + filterEnabled = !filterEnabled; + } + if (name.equals("filter") && isPressed) { + ff.setEnabled(!ff.isEnabled()); + rbf.setEnabled(!rbf.isEnabled()); + } + } + }, "press", "filter"); + + inputManager.addMapping("press", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("filter", new KeyTrigger(KeyInput.KEY_F)); + + } +} diff --git a/JmeTests/src/jme3test/post/TestMultiplesFilters.java b/JmeTests/src/jme3test/post/TestMultiplesFilters.java new file mode 100644 index 0000000..46efd63 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestMultiplesFilters.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.ColorOverlayFilter; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.scene.Spatial; +import com.jme3.util.SkyFactory; +import com.jme3.water.WaterFilter; +import java.io.File; + +public class TestMultiplesFilters extends SimpleApplication { + + private static boolean useHttp = false; + + public static void main(String[] args) { + File file = new File("wildhouse.zip"); + if (!file.exists()) { + useHttp = true; + } + TestMultiplesFilters app = new TestMultiplesFilters(); + app.start(); + } + SSAOFilter ssaoFilter; + FilterPostProcessor fpp; + boolean en = true; + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(6.0344796f, 1.5054002f, 55.572033f)); + cam.setRotation(new Quaternion(0.0016069f, 0.9810479f, -0.008143323f, 0.19358753f)); + + // load sky + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + + // create the geometry and attach it + // load the level from zip or http zip + if (useHttp) { + assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip", HttpZipLocator.class); + } else { + assetManager.registerLocator("wildhouse.zip", ZipLocator.class); + } + Spatial scene = assetManager.loadModel("main.scene"); + + + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.4790551f, -0.39247334f, -0.7851566f)); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + scene.addLight(sun); + + fpp = new FilterPostProcessor(assetManager); + // fpp.setNumSamples(4); + ssaoFilter = new SSAOFilter(0.92f, 2.2f, 0.46f, 0.2f); + final WaterFilter water=new WaterFilter(rootNode,new Vector3f(-0.4790551f, -0.39247334f, -0.7851566f)); + water.setWaterHeight(-20); + SSAOUI ui=new SSAOUI(inputManager,ssaoFilter); + final BloomFilter bloom = new BloomFilter(); + final ColorOverlayFilter overlay = new ColorOverlayFilter(ColorRGBA.LightGray); + + + fpp.addFilter(ssaoFilter); + + fpp.addFilter(water); + + fpp.addFilter(bloom); + + fpp.addFilter(overlay); + + viewPort.addProcessor(fpp); + + rootNode.attachChild(scene); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if ("toggleSSAO".equals(name) && isPressed) { + if (ssaoFilter.isEnabled()) { + ssaoFilter.setEnabled(false); + } else { + ssaoFilter.setEnabled(true); + } + } + if ("toggleWater".equals(name) && isPressed) { + if (water.isEnabled()) { + water.setEnabled(false); + } else { + water.setEnabled(true); + } + } + if ("toggleBloom".equals(name) && isPressed) { + if (bloom.isEnabled()) { + bloom.setEnabled(false); + } else { + bloom.setEnabled(true); + } + } + if ("toggleOverlay".equals(name) && isPressed) { + if (overlay.isEnabled()) { + overlay.setEnabled(false); + } else { + overlay.setEnabled(true); + } + } + } + }, "toggleSSAO", "toggleBloom", "toggleWater","toggleOverlay"); + inputManager.addMapping("toggleSSAO", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("toggleWater", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addMapping("toggleBloom", new KeyTrigger(KeyInput.KEY_3)); + inputManager.addMapping("toggleOverlay", new KeyTrigger(KeyInput.KEY_4)); + + } +} diff --git a/JmeTests/src/jme3test/post/TestPostFilters.java b/JmeTests/src/jme3test/post/TestPostFilters.java new file mode 100644 index 0000000..c2ee5b0 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestPostFilters.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.*; +import com.jme3.renderer.Caps; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import com.jme3.util.TangentBinormalGenerator; + +public class TestPostFilters extends SimpleApplication implements ActionListener { + + private FilterPostProcessor fpp; + private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); + FadeFilter fade; + + public static void main(String[] args) { + TestPostFilters app = new TestPostFilters(); +// AppSettings settings = new AppSettings(true); +// settings.setRenderer(AppSettings.LWJGL_OPENGL2); +// app.setSettings(settings); + app.start(); + } + + public void setupFilters() { + if (renderer.getCaps().contains(Caps.GLSL100)) { + fpp = new FilterPostProcessor(assetManager); + // fpp.setNumSamples(4); + // fpp.setNumSamples(4); + //fpp.addFilter(new ColorOverlayFilter(ColorRGBA.LightGray)); + fpp.addFilter(new RadialBlurFilter()); + fade = new FadeFilter(1.0f); + fpp.addFilter(fade); + + + viewPort.addProcessor(fpp); + } + } + + public void setupSkyBox() { + Texture envMap; + if (renderer.getCaps().contains(Caps.FloatTexture)) { + envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.hdr"); + } else { + envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.jpg"); + } + Spatial sky = SkyFactory.createSky(assetManager, envMap, + new Vector3f(-1f, -1f, -1f), EnvMapType.SphereMap); + rootNode.attachChild(sky); + } + + public void setupLighting() { + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(lightDir); + + dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1)); + + rootNode.addLight(dl); + + dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, 0, -1).normalizeLocal()); + + dl.setColor(new ColorRGBA(.4f, .4f, .4f, 1)); + + // rootNode.addLight(dl); + } + + public void setupFloor() { + Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); + Box floor = new Box(50, 1f, 50); + TangentBinormalGenerator.generate(floor); + floor.scaleTextureCoordinates(new Vector2f(5, 5)); + Geometry floorGeom = new Geometry("Floor", floor); + floorGeom.setMaterial(mat); + floorGeom.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(floorGeom); + } + + public void setupSignpost() { + Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); + Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + signpost.setMaterial(mat); + signpost.rotate(0, FastMath.HALF_PI, 0); + signpost.setLocalTranslation(12, 3.5f, 30); + signpost.setLocalScale(4); + signpost.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(signpost); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(-32.295086f, 54.80136f, 79.59805f)); + cam.setRotation(new Quaternion(0.074364014f, 0.92519957f, -0.24794696f, 0.27748522f)); + + setupLighting(); + setupSkyBox(); + + + setupFloor(); + + setupSignpost(); + + setupFilters(); + + initInput(); + + } + + protected void initInput() { + flyCam.setMoveSpeed(50); + //init input + inputManager.addMapping("fadein", new KeyTrigger(KeyInput.KEY_I)); + inputManager.addListener(this, "fadein"); + inputManager.addMapping("fadeout", new KeyTrigger(KeyInput.KEY_O)); + inputManager.addListener(this, "fadeout"); + + } + + public void onAction(String name, boolean value, float tpf) { + if (name.equals("fadein") && value) { + fade.fadeIn(); + System.out.println("fade in"); + + } + if (name.equals("fadeout") && value) { + fade.fadeOut(); + System.out.println("fade out"); + } + } +} diff --git a/JmeTests/src/jme3test/post/TestPostFiltersCompositing.java b/JmeTests/src/jme3test/post/TestPostFiltersCompositing.java new file mode 100644 index 0000000..817fef0 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestPostFiltersCompositing.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ColorOverlayFilter; +import com.jme3.post.filters.ComposeFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; +import com.jme3.util.SkyFactory; + +/** + * This test showcases the possibility to compose the post filtered outputs of several viewports. + * The usual use case is when you want to apply some post process to the main viewport and then other post process to the gui viewport + * @author Nehon + */ +public class TestPostFiltersCompositing extends SimpleApplication { + + public static void main(String[] args) { + TestPostFiltersCompositing app = new TestPostFiltersCompositing(); +// AppSettings settings = new AppSettings(true); +// settings.putBoolean("GraphicsDebug", false); +// app.setSettings(settings); + app.start(); + + } + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(0.028406568f, 2.015769f, 7.386517f)); + cam.setRotation(new Quaternion(-1.0729783E-5f, 0.9999721f, -0.0073241726f, -0.0014647911f)); + + + makeScene(); + + //Creating the main view port post processor + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(new ColorOverlayFilter(ColorRGBA.Blue)); + viewPort.addProcessor(fpp); + + //creating a frame buffer for the mainviewport + FrameBuffer mainVPFrameBuffer = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1); + Texture2D mainVPTexture = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); + mainVPFrameBuffer.addColorTexture(mainVPTexture); + mainVPFrameBuffer.setDepthBuffer(Image.Format.Depth); + viewPort.setOutputFrameBuffer(mainVPFrameBuffer); + + //creating the post processor for the gui viewport + final FilterPostProcessor guifpp = new FilterPostProcessor(assetManager); + guifpp.setFrameBufferFormat(Image.Format.RGBA8); + guifpp.addFilter(new ColorOverlayFilter(ColorRGBA.Red)); + //this will compose the main viewport texture with the guiviewport back buffer. + //Note that you can switch the order of the filters so that guiviewport filters are applied or not to the main viewport texture + guifpp.addFilter(new ComposeFilter(mainVPTexture)); + + guiViewPort.addProcessor(guifpp); + + //compositing is done by mixing texture depending on the alpha channel, + //it's important that the guiviewport clear color alpha value is set to 0 + guiViewPort.setBackgroundColor(ColorRGBA.BlackNoAlpha); + guiViewPort.setClearColor(true); + + + } + + private void makeScene() { + // load sky + rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap)); + //assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip", HttpZipLocator.class); + Spatial scene = assetManager.loadModel("Models/Test/CornellBox.j3o"); + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(-0.4790551f, -0.39247334f, -0.7851566f)); + scene.addLight(sun); + rootNode.attachChild(scene); + + } +} diff --git a/JmeTests/src/jme3test/post/TestPosterization.java b/JmeTests/src/jme3test/post/TestPosterization.java new file mode 100644 index 0000000..9b6d33f --- /dev/null +++ b/JmeTests/src/jme3test/post/TestPosterization.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ColorOverlayFilter; +import com.jme3.post.filters.PosterizationFilter; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; + +public class TestPosterization extends SimpleApplication { + + Spatial teapot; + PosterizationFilter pf; + + public static void main(String[] args){ + TestPosterization app = new TestPosterization(); + app.start(); + } + + @Override + public void simpleInitApp() { + // put the camera in a bad position + cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -7.139601f)); + cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); + + Material mat = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 15f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); + + Material matSoil = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + matSoil.setFloat("Shininess", 15f); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Gray); + + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(0,0,10); + + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + teapot.setLocalScale(10.0f); + rootNode.attachChild(teapot); + + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(soil); + + DirectionalLight light=new DirectionalLight(); + light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + + // load sky + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/FullskiesBlueClear03.dds", SkyFactory.EnvMapType.CubeMap); + sky.setCullHint(Spatial.CullHint.Never); + rootNode.attachChild(sky); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + int numSamples = getContext().getSettings().getSamples(); + if (numSamples > 0) { + fpp.setNumSamples(numSamples); + } + pf = new PosterizationFilter(); + fpp.addFilter(pf); + + viewPort.addProcessor(fpp); + initInputs(); + + } + + private void initInputs() { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + pf.setEnabled(!pf.isEnabled()); + } + } + }; + + inputManager.addListener(acl, "toggle"); + + } + + + +} diff --git a/JmeTests/src/jme3test/post/TestRenderToCubemap.java b/JmeTests/src/jme3test/post/TestRenderToCubemap.java new file mode 100644 index 0000000..586ea67 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestRenderToCubemap.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.TextureCubeMap; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; + +/** + * Renders a rotating box to a cubemap texture, then applies the cubemap + * texture as a sky. + */ +public class TestRenderToCubemap extends SimpleApplication { + + private Geometry offBox; + private float angle = 0; + private ViewPort offView; + + public static void main(String[] args){ + TestRenderToCubemap app = new TestRenderToCubemap(); + app.start(); + } + + public Texture setupOffscreenView(){ + Camera offCamera = new Camera(512, 512); + + offView = renderManager.createPreView("Offscreen View", offCamera); + offView.setClearFlags(true, true, true); + offView.setBackgroundColor(ColorRGBA.DarkGray); + + // create offscreen framebuffer + FrameBuffer offBuffer = new FrameBuffer(512, 512, 1); + + //setup framebuffer's cam + offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f); + offCamera.setLocation(new Vector3f(0f, 0f, -5f)); + offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y); + + //setup framebuffer's texture + TextureCubeMap offTex = new TextureCubeMap(512, 512, Format.RGBA8); + offTex.setMinFilter(Texture.MinFilter.Trilinear); + offTex.setMagFilter(Texture.MagFilter.Bilinear); + + //setup framebuffer to use texture + offBuffer.setDepthBuffer(Format.Depth); + offBuffer.setMultiTarget(true); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeX); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveX); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeY); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveY); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.NegativeZ); + offBuffer.addColorTexture(offTex, TextureCubeMap.Face.PositiveZ); + + //set viewport to render to offscreen framebuffer + offView.setOutputFrameBuffer(offBuffer); + + // setup framebuffer's scene + Box boxMesh = new Box( 1,1,1); + Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); + offBox = new Geometry("box", boxMesh); + offBox.setMaterial(material); + + // attach the scene to the viewport to be rendered + offView.attachScene(offBox); + + return offTex; + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(3, 3, 3)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + + Texture offTex = setupOffscreenView(); + Spatial sky = SkyFactory.createSky(assetManager, offTex, + EnvMapType.CubeMap); + rootNode.attachChild(sky); + } + + @Override + public void simpleUpdate(float tpf){ + Quaternion q = new Quaternion(); + + angle += tpf; + angle %= FastMath.TWO_PI; + q.fromAngles(angle, 0, angle); + + offBox.setLocalRotation(q); + offBox.updateLogicalState(tpf); + offBox.updateGeometricState(); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/post/TestRenderToMemory.java b/JmeTests/src/jme3test/post/TestRenderToMemory.java new file mode 100644 index 0000000..dd59a1d --- /dev/null +++ b/JmeTests/src/jme3test/post/TestRenderToMemory.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.SceneProcessor; +import com.jme3.profile.AppProfiler; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext.Type; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture2D; +import com.jme3.util.BufferUtils; +import com.jme3.util.Screenshots; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +/** + * This test renders a scene to an offscreen framebuffer, then copies + * the contents to a Swing JFrame. Note that some parts are done inefficently, + * this is done to make the code more readable. + */ +public class TestRenderToMemory extends SimpleApplication implements SceneProcessor { + + private Geometry offBox; + private float angle = 0; + + private FrameBuffer offBuffer; + private ViewPort offView; + private Texture2D offTex; + private Camera offCamera; + private ImageDisplay display; + + private static final int width = 800, height = 600; + + private final ByteBuffer cpuBuf = BufferUtils.createByteBuffer(width * height * 4); + private final byte[] cpuArray = new byte[width * height * 4]; + private final BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_BGR); + + private class ImageDisplay extends JPanel { + + private long t; + private long total; + private int frames; + private int fps; + + @Override + public void paintComponent(Graphics gfx) { + super.paintComponent(gfx); + Graphics2D g2d = (Graphics2D) gfx; + + if (t == 0) + t = timer.getTime(); + +// g2d.setBackground(Color.BLACK); +// g2d.clearRect(0,0,width,height); + + synchronized (image){ + g2d.drawImage(image, null, 0, 0); + } + + long t2 = timer.getTime(); + long dt = t2 - t; + total += dt; + frames ++; + t = t2; + + if (total > timer.getResolution()) { + fps = frames; + total = 0; + frames = 0; + } + + g2d.setColor(Color.white); + g2d.drawString("FPS: "+fps, 0, getHeight() - 100); + } + } + + public static void main(String[] args){ + TestRenderToMemory app = new TestRenderToMemory(); + app.setPauseOnLostFocus(false); + AppSettings settings = new AppSettings(true); + settings.setResolution(1, 1); + app.setSettings(settings); + app.start(Type.OffscreenSurface); + } + + public void createDisplayFrame(){ + SwingUtilities.invokeLater(new Runnable(){ + public void run(){ + JFrame frame = new JFrame("Render Display"); + display = new ImageDisplay(); + display.setPreferredSize(new Dimension(width, height)); + frame.getContentPane().add(display); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.addWindowListener(new WindowAdapter(){ + public void windowClosed(WindowEvent e){ + stop(); + } + }); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setResizable(false); + frame.setVisible(true); + } + }); + } + + public void updateImageContents(){ + cpuBuf.clear(); + renderer.readFrameBuffer(offBuffer, cpuBuf); + + synchronized (image) { + Screenshots.convertScreenShot2(cpuBuf.asIntBuffer(), image); + } + + if (display != null) + display.repaint(); + } + + public void setupOffscreenView(){ + offCamera = new Camera(width, height); + + // create a pre-view. a view that is rendered before the main view + offView = renderManager.createPreView("Offscreen View", offCamera); + offView.setBackgroundColor(ColorRGBA.DarkGray); + offView.setClearFlags(true, true, true); + + // this will let us know when the scene has been rendered to the + // frame buffer + offView.addProcessor(this); + + // create offscreen framebuffer + offBuffer = new FrameBuffer(width, height, 1); + + //setup framebuffer's cam + offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f); + offCamera.setLocation(new Vector3f(0f, 0f, -5f)); + offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y); + + //setup framebuffer's texture +// offTex = new Texture2D(width, height, Format.RGBA8); + + //setup framebuffer to use renderbuffer + // this is faster for gpu -> cpu copies + offBuffer.setDepthBuffer(Format.Depth); + offBuffer.setColorBuffer(Format.RGBA8); +// offBuffer.setColorTexture(offTex); + + //set viewport to render to offscreen framebuffer + offView.setOutputFrameBuffer(offBuffer); + + // setup framebuffer's scene + Box boxMesh = new Box(1, 1, 1); + Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); + offBox = new Geometry("box", boxMesh); + offBox.setMaterial(material); + + // attach the scene to the viewport to be rendered + offView.attachScene(offBox); + } + + @Override + public void simpleInitApp() { + setupOffscreenView(); + createDisplayFrame(); + } + + @Override + public void simpleUpdate(float tpf){ + Quaternion q = new Quaternion(); + angle += tpf; + angle %= FastMath.TWO_PI; + q.fromAngles(angle, 0, angle); + + offBox.setLocalRotation(q); + offBox.updateLogicalState(tpf); + offBox.updateGeometricState(); + } + + public void initialize(RenderManager rm, ViewPort vp) { + } + + public void reshape(ViewPort vp, int w, int h) { + } + + public boolean isInitialized() { + return true; + } + + public void preFrame(float tpf) { + } + + public void postQueue(RenderQueue rq) { + } + + /** + * Update the CPU image's contents after the scene has + * been rendered to the framebuffer. + */ + public void postFrame(FrameBuffer out) { + updateImageContents(); + } + + public void cleanup() { + } + + @Override + public void setProfiler(AppProfiler profiler) { + + } + + +} diff --git a/JmeTests/src/jme3test/post/TestRenderToTexture.java b/JmeTests/src/jme3test/post/TestRenderToTexture.java new file mode 100644 index 0000000..037c959 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestRenderToTexture.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; + +/** + * This test renders a scene to a texture, then displays the texture on a cube. + */ +public class TestRenderToTexture extends SimpleApplication implements ActionListener { + + private static final String TOGGLE_UPDATE = "Toggle Update"; + private Geometry offBox; + private float angle = 0; + private ViewPort offView; + + public static void main(String[] args){ + TestRenderToTexture app = new TestRenderToTexture(); + app.start(); + } + + public Texture setupOffscreenView(){ + Camera offCamera = new Camera(512, 512); + + offView = renderManager.createPreView("Offscreen View", offCamera); + offView.setClearFlags(true, true, true); + offView.setBackgroundColor(ColorRGBA.DarkGray); + + // create offscreen framebuffer + FrameBuffer offBuffer = new FrameBuffer(512, 512, 1); + + //setup framebuffer's cam + offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f); + offCamera.setLocation(new Vector3f(0f, 0f, -5f)); + offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y); + + //setup framebuffer's texture + Texture2D offTex = new Texture2D(512, 512, Format.RGBA8); + offTex.setMinFilter(Texture.MinFilter.Trilinear); + offTex.setMagFilter(Texture.MagFilter.Bilinear); + + //setup framebuffer to use texture + offBuffer.setDepthBuffer(Format.Depth); + offBuffer.setColorTexture(offTex); + + //set viewport to render to offscreen framebuffer + offView.setOutputFrameBuffer(offBuffer); + + // setup framebuffer's scene + Box boxMesh = new Box(1, 1, 1); + Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); + offBox = new Geometry("box", boxMesh); + offBox.setMaterial(material); + + // attach the scene to the viewport to be rendered + offView.attachScene(offBox); + + return offTex; + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(3, 3, 3)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + + //setup main scene + Geometry quad = new Geometry("box", new Box(1, 1, 1)); + + Texture offTex = setupOffscreenView(); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", offTex); + quad.setMaterial(mat); + rootNode.attachChild(quad); + inputManager.addMapping(TOGGLE_UPDATE, new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addListener(this, TOGGLE_UPDATE); + } + + @Override + public void simpleUpdate(float tpf){ + Quaternion q = new Quaternion(); + + if (offView.isEnabled()) { + angle += tpf; + angle %= FastMath.TWO_PI; + q.fromAngles(angle, 0, angle); + + offBox.setLocalRotation(q); + offBox.updateLogicalState(tpf); + offBox.updateGeometricState(); + } + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals(TOGGLE_UPDATE) && isPressed) { + offView.setEnabled(!offView.isEnabled()); + } + } + + +} diff --git a/JmeTests/src/jme3test/post/TestSSAO.java b/JmeTests/src/jme3test/post/TestSSAO.java new file mode 100644 index 0000000..29ad991 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestSSAO.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.scene.Geometry; +import com.jme3.texture.Texture; + +public class TestSSAO extends SimpleApplication { + + Geometry model; + + public static void main(String[] args) { + TestSSAO app = new TestSSAO(); + app.start(); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(68.45442f, 8.235511f, 7.9676695f)); + cam.setRotation(new Quaternion(0.046916496f, -0.69500375f, 0.045538206f, 0.7160271f)); + + + flyCam.setMoveSpeed(50); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Texture diff = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + diff.setWrap(Texture.WrapMode.Repeat); + Texture norm = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"); + norm.setWrap(Texture.WrapMode.Repeat); + mat.setTexture("DiffuseMap", diff); + mat.setTexture("NormalMap", norm); + mat.setFloat("Shininess", 2.0f); + + + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(1.8f, 1.8f, 1.8f, 1.0f)); + + rootNode.addLight(al); + + model = (Geometry) assetManager.loadModel("Models/Sponza/Sponza.j3o"); + model.getMesh().scaleTextureCoordinates(new Vector2f(2, 2)); + + model.setMaterial(mat); + + rootNode.attachChild(model); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + SSAOFilter ssaoFilter = new SSAOFilter(2.9299974f,32.920483f,5.8100376f,0.091000035f);; + ssaoFilter.setApproximateNormals(true); + fpp.addFilter(ssaoFilter); + SSAOUI ui = new SSAOUI(inputManager, ssaoFilter); + + viewPort.addProcessor(fpp); + } + + @Override + public void simpleUpdate(float tpf) { + } +} diff --git a/JmeTests/src/jme3test/post/TestSSAO2.java b/JmeTests/src/jme3test/post/TestSSAO2.java new file mode 100644 index 0000000..678484e --- /dev/null +++ b/JmeTests/src/jme3test/post/TestSSAO2.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.*; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.app.DetailedProfilerState; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.scene.*; +import com.jme3.scene.shape.Box; + +public class TestSSAO2 extends SimpleApplication { + + Geometry model; + + public static void main(String[] args) { + TestSSAO2 app = new TestSSAO2(); + app.start(); + } + + @Override + public void simpleInitApp() { + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1,-1,-1).normalizeLocal()); + rootNode.addLight(dl); + + flyCam.setDragToRotate(true); + setPauseOnLostFocus(false); + + getStateManager().attach(new DetailedProfilerState()); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 16f); + //mat.setBoolean("VertexLighting", true); + + + Geometry floor = new Geometry("floor", new Box(1000,0.1f,1000)); + floor.setMaterial(mat); + rootNode.attachChild(floor); + + Node teapotNode = (Node) assetManager.loadModel("Models/Teapot/Teapot.mesh.xml"); + Geometry teapot = (Geometry) teapotNode.getChild(0); + teapot.setMaterial(mat); +// Sphere sph = new Sphere(16, 16, 4); +// Geometry teapot = new Geometry("teapot", sph); + + + + // show normals as material + //Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + for (int f = 10; f > 3; f--) { + for (int y = -f; y < f; y++) { + for (int x = -f; x < f; x++) { + Geometry clonePot = teapot.clone(); + + //clonePot.setMaterial(mat); + clonePot.setLocalTranslation(x * .5f, 10 - f, y * .5f); + clonePot.setLocalScale(.15f); + + rootNode.attachChild(clonePot); + } + } + } + + cam.setLocation(new Vector3f(10.247649f, 8.275992f, 10.405156f)); + cam.setRotation(new Quaternion(-0.083419204f, 0.90370524f, -0.20599906f, -0.36595422f)); + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + SSAOFilter ssaoFilter = new SSAOFilter(2.9299974f,25f,5.8100376f,0.091000035f); + int numSamples = context.getSettings().getSamples(); + if (numSamples > 0) { + fpp.setNumSamples(numSamples); + } + + //ssaoFilter.setApproximateNormals(true); + fpp.addFilter(ssaoFilter); + SSAOUI ui = new SSAOUI(inputManager, ssaoFilter); + + viewPort.addProcessor(fpp); + } + + @Override + public void simpleUpdate(float tpf) { + } +} diff --git a/JmeTests/src/jme3test/post/TestToneMapFilter.java b/JmeTests/src/jme3test/post/TestToneMapFilter.java new file mode 100644 index 0000000..2d12958 --- /dev/null +++ b/JmeTests/src/jme3test/post/TestToneMapFilter.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.ToneMapFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; + +public class TestToneMapFilter extends SimpleApplication { + + private boolean enabled = true; + private FilterPostProcessor fpp; + private ToneMapFilter toneMapFilter; + private float whitePointLog = 1f; + + public static void main(String[] args){ + TestToneMapFilter app = new TestToneMapFilter(); + AppSettings settings = new AppSettings(true); + + // Must turn on gamma correction, as otherwise it looks too dark. + settings.setGammaCorrection(true); + + app.setSettings(settings); + app.start(); + } + + public Geometry createHDRBox(){ + Box boxMesh = new Box(1, 1, 1); + Geometry box = new Geometry("Box", boxMesh); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Textures/HdrTest/Memorial.hdr")); + box.setMaterial(mat); + return box; + } + + @Override + public void simpleInitApp() { + System.out.println("== Tone Mapping Sample =="); + System.out.println(" SPACE:\tToggle tone-mapping OFF or ON"); + System.out.println(" Y:\tIncrease white-point"); + System.out.println(" H:\tDecrease white-point"); + + fpp = new FilterPostProcessor(assetManager); + toneMapFilter = new ToneMapFilter(); + fpp.addFilter(toneMapFilter); + viewPort.addProcessor(fpp); + + rootNode.attachChild(createHDRBox()); + + cam.setLocation(new Vector3f(0f,0f,3f)); + + initInputs(); + } + + private void initInputs() { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("WhitePointUp", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("WhitePointDown", new KeyTrigger(KeyInput.KEY_H)); + + ActionListener acl = new ActionListener() { + + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + if (enabled) { + enabled = false; + viewPort.removeProcessor(fpp); + System.out.println("Tone Mapping OFF"); + } else { + enabled = true; + viewPort.addProcessor(fpp); + System.out.println("Tone Mapping ON"); + } + } + } + }; + + AnalogListener anl = new AnalogListener() { + + public void onAnalog(String name, float isPressed, float tpf) { + if (name.equals("WhitePointUp")) { + whitePointLog += tpf * 1.0; + if (whitePointLog > 4f) { + whitePointLog = 4f; + } + float wp = FastMath.exp(whitePointLog); + toneMapFilter.setWhitePoint(new Vector3f(wp, wp, wp)); + System.out.println("White point: " + wp); + } + + if (name.equals("WhitePointDown")) { + whitePointLog -= tpf * 1.0; + if (whitePointLog < -4f) { + whitePointLog = -4f; + } + float wp = FastMath.exp(whitePointLog); + toneMapFilter.setWhitePoint(new Vector3f(wp, wp, wp)); + System.out.println("White point: " + wp); + } + } + }; + + inputManager.addListener(acl, "toggle"); + inputManager.addListener(anl, "WhitePointUp", "WhitePointDown"); + } +} diff --git a/JmeTests/src/jme3test/post/TestTransparentCartoonEdge.java b/JmeTests/src/jme3test/post/TestTransparentCartoonEdge.java new file mode 100644 index 0000000..46ba0ac --- /dev/null +++ b/JmeTests/src/jme3test/post/TestTransparentCartoonEdge.java @@ -0,0 +1,97 @@ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.CartoonEdgeFilter; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Texture; + +public class TestTransparentCartoonEdge extends SimpleApplication { + + public static void main(String[] args){ + TestTransparentCartoonEdge app = new TestTransparentCartoonEdge(); + app.start(); + } + + public void simpleInitApp() { + renderManager.setAlphaToCoverage(true); + cam.setLocation(new Vector3f(0.14914267f, 0.58147097f, 4.7686534f)); + cam.setRotation(new Quaternion(-0.0044764364f, 0.9767943f, 0.21314798f, 0.020512417f)); + +// cam.setLocation(new Vector3f(2.0606942f, 3.20342f, 6.7860126f)); +// cam.setRotation(new Quaternion(-0.017481906f, 0.98241085f, -0.12393151f, -0.13857932f)); + + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + Quad q = new Quad(20, 20); + q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(5)); + Geometry geom = new Geometry("floor", q); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + geom.setMaterial(mat); + + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.center(); + geom.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(geom); + + // create the geometry and attach it + Spatial teaGeom = assetManager.loadModel("Models/Tree/Tree.mesh.j3o"); + teaGeom.setQueueBucket(Bucket.Transparent); + teaGeom.setShadowMode(ShadowMode.Cast); + makeToonish(teaGeom); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(2)); + rootNode.addLight(al); + + DirectionalLight dl1 = new DirectionalLight(); + dl1.setDirection(new Vector3f(1, -1, 1).normalizeLocal()); + dl1.setColor(new ColorRGBA(0.965f, 0.949f, 0.772f, 1f).mult(0.7f)); + rootNode.addLight(dl1); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.965f, 0.949f, 0.772f, 1f).mult(0.7f)); + rootNode.addLight(dl); + + rootNode.attachChild(teaGeom); + + FilterPostProcessor fpp=new FilterPostProcessor(assetManager); + CartoonEdgeFilter toon=new CartoonEdgeFilter(); + toon.setEdgeWidth(0.5f); + toon.setEdgeIntensity(1.0f); + toon.setNormalThreshold(0.8f); + fpp.addFilter(toon); + viewPort.addProcessor(fpp); + } + + public void makeToonish(Spatial spatial){ + if (spatial instanceof Node){ + Node n = (Node) spatial; + for (Spatial child : n.getChildren()) + makeToonish(child); + }else if (spatial instanceof Geometry){ + Geometry g = (Geometry) spatial; + Material m = g.getMaterial(); + if (m.getMaterialDef().getName().equals("Phong Lighting")){ + Texture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); +// t.setMinFilter(Texture.MinFilter.NearestNoMipMaps); +// t.setMagFilter(Texture.MagFilter.Nearest); + m.setTexture("ColorRamp", t); + m.setBoolean("UseMaterialColors", true); + m.setColor("Specular", ColorRGBA.Black); + m.setColor("Diffuse", ColorRGBA.White); + m.setBoolean("VertexLighting", true); + } + } + } +} diff --git a/JmeTests/src/jme3test/post/TestTransparentSSAO.java b/JmeTests/src/jme3test/post/TestTransparentSSAO.java new file mode 100644 index 0000000..310cc2d --- /dev/null +++ b/JmeTests/src/jme3test/post/TestTransparentSSAO.java @@ -0,0 +1,76 @@ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.util.TangentBinormalGenerator; + +public class TestTransparentSSAO extends SimpleApplication { + + public static void main(String[] args) { + TestTransparentSSAO app = new TestTransparentSSAO(); + app.start(); + } + + public void simpleInitApp() { + renderManager.setAlphaToCoverage(true); + cam.setLocation(new Vector3f(0.14914267f, 0.58147097f, 4.7686534f)); + cam.setRotation(new Quaternion(-0.0044764364f, 0.9767943f, 0.21314798f, 0.020512417f)); + +// cam.setLocation(new Vector3f(2.0606942f, 3.20342f, 6.7860126f)); +// cam.setRotation(new Quaternion(-0.017481906f, 0.98241085f, -0.12393151f, -0.13857932f)); + + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + + Quad q = new Quad(20, 20); + q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(5)); + Geometry geom = new Geometry("floor", q); + Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); + geom.setMaterial(mat); + + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.center(); + geom.setShadowMode(ShadowMode.Receive); + TangentBinormalGenerator.generate(geom); + rootNode.attachChild(geom); + + // create the geometry and attach it + Spatial teaGeom = assetManager.loadModel("Models/Tree/Tree.mesh.j3o"); + teaGeom.setQueueBucket(Bucket.Transparent); + teaGeom.setShadowMode(ShadowMode.Cast); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(2)); + rootNode.addLight(al); + + DirectionalLight dl1 = new DirectionalLight(); + dl1.setDirection(new Vector3f(1, -1, 1).normalizeLocal()); + dl1.setColor(new ColorRGBA(0.965f, 0.949f, 0.772f, 1f).mult(0.7f)); + rootNode.addLight(dl1); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + dl.setColor(new ColorRGBA(0.965f, 0.949f, 0.772f, 1f).mult(0.7f)); + rootNode.addLight(dl); + + rootNode.attachChild(teaGeom); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + SSAOFilter ssao = new SSAOFilter();//0.49997783f, 42.598858f, 35.999966f, 0.39299846f + fpp.addFilter(ssao); + + SSAOUI ui = new SSAOUI(inputManager, ssao); + + viewPort.addProcessor(fpp); + } +} diff --git a/JmeTests/src/jme3test/renderer/TestAspectRatio.java b/JmeTests/src/jme3test/renderer/TestAspectRatio.java new file mode 100644 index 0000000..bdb5267 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestAspectRatio.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +/** + * Simple application to test a viewport/camera with a different aspect ratio + * than the display -- issue #357. The cube should render as a blue square, not + * a rectangle. + * + * Based closely on the test case submitted by slyh on September 28, 2015. + */ +public class TestAspectRatio extends SimpleApplication { + + public static void main(String[] args) { + new TestAspectRatio().start(); + } + + @Override + public void simpleInitApp() { + Geometry cube = new Geometry("blue cube", new Box(1, 1, 1)); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + cube.setMaterial(mat); + + rootNode.attachChild(cube); + + // Trying to update the viewport: + cam.setViewPortBottom(0.5f); + cam.resize(640, 480 / 2, false); + cam.setFrustumPerspective(40, 640f / (480 / 2), 0.05f, 500f); + cam.update(); + } +} diff --git a/JmeTests/src/jme3test/renderer/TestBlendEquations.java b/JmeTests/src/jme3test/renderer/TestBlendEquations.java new file mode 100644 index 0000000..9335912 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestBlendEquations.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; + +public class TestBlendEquations extends SimpleApplication { + + public static void main(String[] args) { + TestBlendEquations app = new TestBlendEquations(); + app.start(); + } + + public void simpleInitApp() { + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teaGeom.scale(6); + teaGeom.getMaterial().getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Add); + teaGeom.move(0, -2f, 0); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.Red); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA(0.5f, 0f, 1f, 0.3f)); + mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Color); + mat.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Subtract); + + Geometry geo = new Geometry("BottomLeft", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(0, 0, 1); + + guiNode.attachChild(geo); + + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.ReverseSubtract); + m.setColor("Color", new ColorRGBA(0.0f, 1f, 1.f, 1f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.AlphaAdditive); + + geo = new Geometry("BottomRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, 0, 1); + + guiNode.attachChild(geo); + + m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.getAdditionalRenderState().setBlendEquation(RenderState.BlendEquation.Min); + m.setColor("Color", new ColorRGBA(0.3f, 0f, 0.1f, 0.3f)); + m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Additive); + + geo = new Geometry("TopRight", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(m); + geo.setQueueBucket(RenderQueue.Bucket.Gui); + geo.setLocalTranslation(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2, 1); + + guiNode.attachChild(geo); + + geo = new Geometry("OverTeaPot", new Quad(guiViewPort.getCamera().getWidth() / 2, guiViewPort.getCamera().getHeight() / 2)); + geo.setMaterial(mat); + geo.setQueueBucket(RenderQueue.Bucket.Transparent); + geo.setLocalTranslation(0, -100, 5); + + rootNode.attachChild(geo); + + } + + +} diff --git a/JmeTests/src/jme3test/renderer/TestDepthFuncChange.java b/JmeTests/src/jme3test/renderer/TestDepthFuncChange.java new file mode 100644 index 0000000..1bacf78 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestDepthFuncChange.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +public class TestDepthFuncChange extends SimpleApplication { + + public static void main(String[] args) { + TestDepthFuncChange app = new TestDepthFuncChange(); + app.start(); + } + + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + flyCam.setMoveSpeed(20); + + + //top of the screen + //default depth func (less or equal) rendering. + //2 cubes, a blue and a red. the red cube is offset by 0.2 WU to the right + //the red cube is put in the transparent bucket to be sure it's rendered after the blue one (but there is no transparency involved). + //You should see a small part of the blue cube on the left and the whole red cube + Box boxshape1 = new Box(1f, 1f, 1f); + Geometry cube1 = new Geometry("box", boxshape1); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + + cube1.setMaterial(mat); + rootNode.attachChild(cube1); + cube1.move(0, 1.5f, 0); + + Geometry cube2 = cube1.clone(true); + cube2.move(0.2f, 0 , 0); + cube2.setQueueBucket(RenderQueue.Bucket.Transparent); + cube2.getMaterial().setColor("Color", ColorRGBA.Red); + rootNode.attachChild(cube2); + + //Bottom of the screen + //here the 2 cubes are clonned and the depthFunc for the red cube's material is set to Less + //You should see the whole bleu cube and a small part of the red cube on the right + Geometry cube3 = cube1.clone(); + Geometry cube4 = cube2.clone(true); + cube4.getMaterial().getAdditionalRenderState().setDepthFunc(RenderState.TestFunction.Less); + cube3.move(0,-3,0); + cube4.move(0,-3,0); + rootNode.attachChild(cube3); + rootNode.attachChild(cube4); + + //Note that if you move the camera z fighting will occur but that's expected. + + + } +} diff --git a/JmeTests/src/jme3test/renderer/TestDepthStencil.java b/JmeTests/src/jme3test/renderer/TestDepthStencil.java new file mode 100644 index 0000000..a2a09d4 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestDepthStencil.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2009-2014 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture2D; +import com.jme3.ui.Picture; + +public class TestDepthStencil extends SimpleApplication { + + private boolean enableStencil = false; + + private Node fbNode = new Node("Framebuffer Node"); + private FrameBuffer fb; + + public static void main(String[] args){ + TestDepthStencil app = new TestDepthStencil(); + app.start(); + } + + @Override + public void simpleInitApp() { + int w = settings.getWidth(); + int h = settings.getHeight(); + + //setup framebuffer + fb = new FrameBuffer(w, h, 1); + + Texture2D fbTex = new Texture2D(w, h, Format.RGB8); + fb.setDepthBuffer(Format.Depth24Stencil8); + fb.setColorTexture(fbTex); + + // setup framebuffer's scene + Sphere sphMesh = new Sphere(20, 20, 1); + Material solidColor = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + + final Geometry sphere = new Geometry("sphere", sphMesh); + sphere.setMaterial(solidColor); + fbNode.attachChild(sphere); + + sphere.addControl(new AbstractControl() { + @Override + protected void controlUpdate(float tpf) { + Material mat = sphere.getMaterial(); + mat.getAdditionalRenderState().setStencil(enableStencil, + RenderState.StencilOperation.Keep, RenderState.StencilOperation.Keep, RenderState.StencilOperation.Keep, + RenderState.StencilOperation.Keep, RenderState.StencilOperation.Keep, RenderState.StencilOperation.Keep, + RenderState.TestFunction.Never, RenderState.TestFunction.Never + //TestFunction.Always, TestFunction.Always + ); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } + }); + + //setup main scene + Picture p = new Picture("Picture"); + p.setPosition(0, 0); + p.setWidth(w); + p.setHeight(h); + p.setTexture(assetManager, fbTex, false); + + rootNode.attachChild(p); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + ActionListener acl = new ActionListener() { + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("toggle") && keyPressed) { + if (enableStencil) { + enableStencil = false; + System.out.println("Stencil Enabled (model should be hidden)"); + } else { + enableStencil = true; + System.out.println("Stencil Disabled (model should be visible)"); + } + } + } + }; + inputManager.addListener(acl, "toggle"); + + System.out.println("Press space to toggle stencil"); + } + + @Override + public void simpleUpdate(float tpf){ + fbNode.updateLogicalState(tpf); + fbNode.updateGeometricState(); + } + + @Override + public void simpleRender(RenderManager rm){ + Renderer r = rm.getRenderer(); + + //do FBO rendering + r.setFrameBuffer(fb); + + rm.setCamera(cam, false); // FBO uses current camera + r.clearBuffers(true, true, true); + rm.renderScene(fbNode, viewPort); + rm.flushQueue(viewPort); + + //go back to default rendering and let + //SimpleApplication render the default scene + r.setFrameBuffer(null); + } + +} diff --git a/JmeTests/src/jme3test/renderer/TestInconsistentCompareDetection.java b/JmeTests/src/jme3test/renderer/TestInconsistentCompareDetection.java new file mode 100644 index 0000000..c1f99b3 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestInconsistentCompareDetection.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009-2014 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.texture.Texture; + +/** + * Changes a material's texture from another thread while it is rendered. + * This should trigger the sorting function's inconsistent compare detection. + * + * @author Kirill Vainer + */ +public class TestInconsistentCompareDetection extends SimpleApplication { + + private static Texture t1, t2; + + public static void main(String[] args){ + TestInconsistentCompareDetection app = new TestInconsistentCompareDetection(); + app.start(); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(-11.674385f, 7.892636f, 33.133106f)); + cam.setRotation(new Quaternion(0.06426433f, 0.90940624f, -0.15329266f, 0.38125014f)); + + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setColor("Color", ColorRGBA.White); + + t1 = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + t2 = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); + + Box b = new Box(1, 1, 1); + + for (int x = 0; x < 12; x++) { + for (int y = 0; y < 12; y++) { + Geometry g = new Geometry("g_" + x + "_" + y, b); + Node monkey = new Node("n_" + x + "_" + y); + monkey.attachChild(g); + monkey.move(x * 2, 0, y * 2); + + Material newMat = m.clone(); + g.setMaterial(newMat); + + if (FastMath.rand.nextBoolean()) { + newMat.setTexture("ColorMap", t1); + } else { + newMat.setTexture("ColorMap", t2); + } + + rootNode.attachChild(monkey); + } + } + + Thread evilThread = new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + } + + // begin randomly changing textures after 1 sec. + while (true) { + for (Spatial child : rootNode.getChildren()) { + Geometry g = (Geometry) (((Node)child).getChild(0)); + Material m = g.getMaterial(); + Texture curTex = m.getTextureParam("ColorMap").getTextureValue(); + if (curTex == t1) { + m.setTexture("ColorMap", t2); + } else { + m.setTexture("ColorMap", t1); + } + } + } + } + }); + evilThread.setDaemon(true); + evilThread.start(); + } +} + diff --git a/JmeTests/src/jme3test/renderer/TestMultiViews.java b/JmeTests/src/jme3test/renderer/TestMultiViews.java new file mode 100644 index 0000000..b098ead --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestMultiViews.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; + +public class TestMultiViews extends SimpleApplication { + + public static void main(String[] args) { + TestMultiViews app = new TestMultiViews(); + app.start(); + } + + public void simpleInitApp() { + // create the geometry and attach it + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + teaGeom.scale(3); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + // Setup first view + viewPort.setBackgroundColor(ColorRGBA.Blue); + cam.setViewPort(.5f, 1f, 0f, 0.5f); + cam.setLocation(new Vector3f(3.3212643f, 4.484704f, 4.2812433f)); + cam.setRotation(new Quaternion(-0.07680723f, 0.92299235f, -0.2564353f, -0.27645364f)); + + // Setup second view + Camera cam2 = cam.clone(); + cam2.setViewPort(0f, 0.5f, 0f, 0.5f); + cam2.setLocation(new Vector3f(-0.10947256f, 1.5760219f, 4.81758f)); + cam2.setRotation(new Quaternion(0.0010108891f, 0.99857414f, -0.04928594f, 0.020481428f)); + + ViewPort view2 = renderManager.createMainView("Bottom Left", cam2); + view2.setClearFlags(true, true, true); + view2.attachScene(rootNode); + + // Setup third view + Camera cam3 = cam.clone(); + cam3.setViewPort(0f, .5f, .5f, 1f); + cam3.setLocation(new Vector3f(0.2846221f, 6.4271426f, 0.23380789f)); + cam3.setRotation(new Quaternion(0.004381671f, 0.72363687f, -0.69015175f, 0.0045953835f)); + + ViewPort view3 = renderManager.createMainView("Top Left", cam3); + view3.setClearFlags(true, true, true); + view3.attachScene(rootNode); + + // Setup fourth view + Camera cam4 = cam.clone(); + cam4.setViewPort(.5f, 1f, .5f, 1f); + cam4.setLocation(new Vector3f(4.775564f, 1.4548365f, 0.11491505f)); + cam4.setRotation(new Quaternion(0.02356979f, -0.74957186f, 0.026729556f, 0.66096294f)); + + ViewPort view4 = renderManager.createMainView("Top Right", cam4); + view4.setClearFlags(true, true, true); + view4.attachScene(rootNode); + + //test multiview for gui + guiViewPort.getCamera().setViewPort(.5f, 1f, .5f, 1f); + + // Setup second gui view + Camera guiCam2 = guiViewPort.getCamera().clone(); + guiCam2.setViewPort(0f, 0.5f, 0f, 0.5f); + ViewPort guiViewPort2 = renderManager.createPostView("Gui 2", guiCam2); + guiViewPort2.setClearFlags(false, false, false); + guiViewPort2.attachScene(guiViewPort.getScenes().get(0)); + + } +} diff --git a/JmeTests/src/jme3test/renderer/TestParallelProjection.java b/JmeTests/src/jme3test/renderer/TestParallelProjection.java new file mode 100644 index 0000000..5fc7ab0 --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestParallelProjection.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; + +public class TestParallelProjection extends SimpleApplication implements AnalogListener { + + private float frustumSize = 1; + + public static void main(String[] args){ + TestParallelProjection app = new TestParallelProjection(); + app.start(); + } + + public void simpleInitApp() { + Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); + + DirectionalLight dl = new DirectionalLight(); + dl.setColor(ColorRGBA.White); + dl.setDirection(Vector3f.UNIT_XYZ.negate()); + + rootNode.addLight(dl); + rootNode.attachChild(teaGeom); + + // Setup first view + cam.setParallelProjection(true); + float aspect = (float) cam.getWidth() / cam.getHeight(); + cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize); + + inputManager.addListener(this, "Size+", "Size-"); + inputManager.addMapping("Size+", new KeyTrigger(KeyInput.KEY_W)); + inputManager.addMapping("Size-", new KeyTrigger(KeyInput.KEY_S)); + } + + public void onAnalog(String name, float value, float tpf) { + // Instead of moving closer/farther to object, we zoom in/out. + if (name.equals("Size-")) + frustumSize += 0.3f * tpf; + else + frustumSize -= 0.3f * tpf; + + float aspect = (float) cam.getWidth() / cam.getHeight(); + cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize); + } +} diff --git a/JmeTests/src/jme3test/renderer/TestSplitScreen.java b/JmeTests/src/jme3test/renderer/TestSplitScreen.java new file mode 100644 index 0000000..fe6390a --- /dev/null +++ b/JmeTests/src/jme3test/renderer/TestSplitScreen.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009-2017 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.renderer; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; + +/** + * Simple application to test split-screen rendering. Clicking with LMB toggles + * between a single camera/viewport (cam) and split screen (leftCam plus + * rightCam). See issue #357. + */ +public class TestSplitScreen extends SimpleApplication implements ActionListener { + + boolean splitScreen = false; + Box mesh = new Box(1f, 1f, 1f); + Camera leftCam, rightCam; + Node leftScene = new Node("left scene"); + ViewPort leftView, rightView; + + @Override + public void simpleInitApp() { + flyCam.setEnabled(false); + + Geometry blueBox = new Geometry("blue box", mesh); + Material blueMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + blueMat.setColor("Color", ColorRGBA.Blue); + blueBox.setMaterial(blueMat); + rootNode.attachChild(blueBox); + + rightCam = cam.clone(); + rightCam.setViewPort(0.5f, 1f, 0f, 1f); + + rightView = renderManager.createMainView("right", rightCam); + rightView.setClearFlags(true, true, true); + rightView.setEnabled(false); + rightView.attachScene(rootNode); + + Geometry redBox = new Geometry("red box", mesh); + Material redMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + redMat.setColor("Color", ColorRGBA.Red); + redBox.setMaterial(redMat); + leftScene.attachChild(redBox); + + leftCam = cam.clone(); + leftCam.setViewPort(0f, 0.5f, 0f, 1f); + + leftView = renderManager.createMainView("left", leftCam); + leftView.setClearFlags(true, true, true); + leftView.setEnabled(false); + leftView.attachScene(leftScene); + + inputManager.addMapping("lmb", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(this, "lmb"); + } + + @Override + public void onAction(String name, boolean keyPressed, float tpf) { + if (name.equals("lmb") && !keyPressed) { + splitScreen = !splitScreen; + viewPort.setEnabled(!splitScreen); + leftView.setEnabled(splitScreen); + rightView.setEnabled(splitScreen); + } + } + + @Override + public void simpleUpdate(float tpf) { + leftScene.updateLogicalState(tpf); + leftScene.updateGeometricState(); + } + + public static void main(String[] args) { + TestSplitScreen app = new TestSplitScreen(); + app.start(); + } +} diff --git a/JmeTests/src/jme3test/scene/TestLineWidthRenderState.java b/JmeTests/src/jme3test/scene/TestLineWidthRenderState.java new file mode 100644 index 0000000..6bd6298 --- /dev/null +++ b/JmeTests/src/jme3test/scene/TestLineWidthRenderState.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.scene; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +public class TestLineWidthRenderState extends SimpleApplication { + + private Material mat; + + public static void main(String[] args){ + TestLineWidthRenderState app = new TestLineWidthRenderState(); + app.start(); + } + + + + @Override + public void simpleInitApp() { + setDisplayFps(false); + setDisplayStatView(false); + cam.setLocation(new Vector3f(5.5826545f, 3.6192513f, 8.016988f)); + cam.setRotation(new Quaternion(-0.04787097f, 0.9463123f, -0.16569641f, -0.27339742f)); + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + mat.getAdditionalRenderState().setWireframe(true); + mat.getAdditionalRenderState().setLineWidth(2); + geom.setMaterial(mat); + rootNode.attachChild(geom); + + inputManager.addListener(new ActionListener() { + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if(name.equals("up") && isPressed){ + mat.getAdditionalRenderState().setLineWidth(mat.getAdditionalRenderState().getLineWidth() + 1); + } + if(name.equals("down") && isPressed){ + mat.getAdditionalRenderState().setLineWidth(Math.max(mat.getAdditionalRenderState().getLineWidth() - 1, 1)); + } + } + }, "up", "down"); + inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_J)); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/scene/TestRefreshFlagBug.java b/JmeTests/src/jme3test/scene/TestRefreshFlagBug.java new file mode 100644 index 0000000..6c8d4d8 --- /dev/null +++ b/JmeTests/src/jme3test/scene/TestRefreshFlagBug.java @@ -0,0 +1,45 @@ +package jme3test.scene; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; + +public class TestRefreshFlagBug extends SimpleApplication { + + private float time = 0; + private boolean attached = false; + private Node inBetweenNode; + + public static void main(String[] args) { + TestRefreshFlagBug app = new TestRefreshFlagBug(); + app.start(); + } + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + if (time > 5 && !attached) { + attached = true; + + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + geom.setMaterial(mat); + + inBetweenNode.attachChild(geom); + + // the refresh flags become corrupted here ... + inBetweenNode.getWorldBound(); + } + } + + @Override + public void simpleInitApp() { + inBetweenNode = new Node("In Between Node"); + rootNode.attachChild(inBetweenNode); + + flyCam.setDragToRotate(true); + } +} diff --git a/JmeTests/src/jme3test/scene/TestSceneLoading.java b/JmeTests/src/jme3test/scene/TestSceneLoading.java new file mode 100644 index 0000000..2567d94 --- /dev/null +++ b/JmeTests/src/jme3test/scene/TestSceneLoading.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.scene; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.SkyFactory; +import java.io.File; + +public class TestSceneLoading extends SimpleApplication { + + private Sphere sphereMesh = new Sphere(32, 32, 10, false, true); + private Geometry sphere = new Geometry("Sky", sphereMesh); + private static boolean useHttp = false; + + public static void main(String[] args) { + + TestSceneLoading app = new TestSceneLoading(); + app.start(); + } + + @Override + public void simpleUpdate(float tpf){ + sphere.setLocalTranslation(cam.getLocation()); + } + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(10); + + // load sky + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + + File file = new File("wildhouse.zip"); + if (!file.exists()) { + useHttp = true; + } + // create the geometry and attach it + // load the level from zip or http zip + if (useHttp) { + assetManager.registerLocator("https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/wildhouse.zip", HttpZipLocator.class); + } else { + assetManager.registerLocator("wildhouse.zip", ZipLocator.class); + } + Spatial scene = assetManager.loadModel("main.scene"); + + AmbientLight al = new AmbientLight(); + scene.addLight(al); + + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(0.69077975f, -0.6277887f, -0.35875428f).normalizeLocal()); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + scene.addLight(sun); + + rootNode.attachChild(scene); + } +} diff --git a/JmeTests/src/jme3test/scene/TestSceneStress.java b/JmeTests/src/jme3test/scene/TestSceneStress.java new file mode 100644 index 0000000..46d611e --- /dev/null +++ b/JmeTests/src/jme3test/scene/TestSceneStress.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.scene; + +import com.jme3.app.BasicProfilerState; +import com.jme3.app.DebugKeysAppState; +import com.jme3.app.FlyCamAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.app.StatsAppState; +import com.jme3.app.state.ScreenshotAppState; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Box; +import java.util.Random; + + +/** + * Tests a deep scene with an unrecommended amount of objects. + * + * @author Paul Speed + */ +public class TestSceneStress extends SimpleApplication { + + private static Box BOX = new Box(2f, 0.5f, 0.5f); + + private Material mat; + private Random random = new Random(0); + + private int totalNodes = 0; + private int totalGeometry = 0; + private int totalControls = 0; + + public static void main( String... args ) { + + TestSceneStress test = new TestSceneStress(); + test.start(); + } + + public TestSceneStress() { + super(new StatsAppState(), new DebugKeysAppState(), new BasicProfilerState(false), + new FlyCamAppState(), + new ScreenshotAppState("", System.currentTimeMillis())); + } + + @Override + public void simpleInitApp() { + + stateManager.getState(FlyCamAppState.class).getCamera().setMoveSpeed(10); + + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Blue); + + // Create a deep, mostly static scene + Spatial oct = createOctSplit("root", 500, 5); + + rootNode.attachChild(oct); + + // Position to see most of it + cam.setLocation(new Vector3f(400.8009f, 370.16455f, -408.17984f)); + cam.setRotation(new Quaternion(0.24906662f, -0.3756747f, 0.105560325f, 0.88639235f)); + + System.out.println("Total nodes:" + totalNodes + " Total Geometry:" + totalGeometry + " Total controls:" + totalControls ); + } + + protected Spatial createOctSplit( String name, int size, int depth ) { + + if( depth == 0 ) { + // Done splitting + Geometry geom = new Geometry(name, BOX); + totalGeometry++; + geom.setMaterial(mat); + + if( random.nextFloat() < 0.01 ) { + RotatorControl control = new RotatorControl(random.nextFloat(), random.nextFloat(), random.nextFloat()); + geom.addControl(control); + totalControls++; + } + + return geom; + } + + Node root = new Node(name); + totalNodes++; + + int half = size / 2; + float quarter = half * 0.5f; + + for( int i = 0; i < 2; i++ ) { + float x = i * half - quarter; + for( int j = 0; j < 2; j++ ) { + float y = j * half - quarter; + for( int k = 0; k < 2; k++ ) { + float z = k * half - quarter; + + Spatial child = createOctSplit(name + "(" + i + ", " + j + ", " + k + ")", + half, depth - 1); + child.setLocalTranslation(x, y, z); + root.attachChild(child); + } + } + } + + return root; + } + + private class RotatorControl extends AbstractControl { + private float[] rotate; + + public RotatorControl( float... rotate ) { + this.rotate = rotate; + } + + @Override + protected void controlUpdate( float tpf ) { + if( spatial != null ) { + spatial.rotate(rotate[0] * tpf, rotate[1] * tpf, rotate[2] * tpf); + } + } + + @Override + protected void controlRender( RenderManager rm, ViewPort vp ) { + } + } +} diff --git a/JmeTests/src/jme3test/scene/TestUserData.java b/JmeTests/src/jme3test/scene/TestUserData.java new file mode 100644 index 0000000..59cf6d3 --- /dev/null +++ b/JmeTests/src/jme3test/scene/TestUserData.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.scene; + +import com.jme3.app.SimpleApplication; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +public class TestUserData extends SimpleApplication { + + public static void main(String[] args) { + TestUserData app = new TestUserData(); + app.start(); + } + + public void simpleInitApp() { + Node scene = (Node) assetManager.loadModel("Scenes/DotScene/DotScene.scene"); + System.out.println("Scene: " + scene); + + Spatial testNode = scene.getChild("TestNode"); + System.out.println("TestNode: "+ testNode); + + for (String key : testNode.getUserDataKeys()){ + System.out.println("Property " + key + " = " + testNode.getUserData(key)); + } + } +} diff --git a/JmeTests/src/jme3test/scene/instancing/TestInstanceNode.java b/JmeTests/src/jme3test/scene/instancing/TestInstanceNode.java new file mode 100644 index 0000000..3713408 --- /dev/null +++ b/JmeTests/src/jme3test/scene/instancing/TestInstanceNode.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.scene.instancing; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Spatial; +import com.jme3.scene.Node; +import com.jme3.scene.instancing.InstancedGeometry; +import com.jme3.scene.instancing.InstancedNode; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.system.AppSettings; + +public class TestInstanceNode extends SimpleApplication { + + private Mesh mesh1; + private Mesh mesh2; + private final Material[] materials = new Material[6]; + private Node instancedNode; + private float time = 0; + private boolean INSTANCING = true; + + public static void main(String[] args){ + TestInstanceNode app = new TestInstanceNode(); + AppSettings settings = new AppSettings(true); + settings.setVSync(false); + app.setSettings(settings); + app.start(); + } + + private Geometry createInstance(float x, float z) { + Mesh mesh; + if (FastMath.nextRandomInt(0, 1) == 1) mesh = mesh2; + else mesh = mesh1; + Geometry geometry = new Geometry("randomGeom", mesh); + geometry.setMaterial(materials[FastMath.nextRandomInt(0, materials.length - 1)]); + geometry.setLocalTranslation(x, 0, z); + return geometry; + } + + @Override + public void simpleInitApp() { + mesh1 = new Sphere(13, 13, 0.4f, true, false); + mesh2 = new Box(0.4f, 0.4f, 0.4f); + + materials[0] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[0].setBoolean("UseInstancing", INSTANCING); + materials[0].setColor("Color", ColorRGBA.Red); + + materials[1] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[1].setBoolean("UseInstancing", INSTANCING); + materials[1].setColor("Color", ColorRGBA.Green); + + materials[2] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[2].setBoolean("UseInstancing", INSTANCING); + materials[2].setColor("Color", ColorRGBA.Blue); + + materials[3] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[3].setBoolean("UseInstancing", INSTANCING); + materials[3].setColor("Color", ColorRGBA.Cyan); + + materials[4] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[4].setBoolean("UseInstancing", INSTANCING); + materials[4].setColor("Color", ColorRGBA.Magenta); + + materials[5] = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + materials[5].setBoolean("UseInstancing", INSTANCING); + materials[5].setColor("Color", ColorRGBA.Yellow); + + instancedNode = new InstancedNode("instanced_node"); + + rootNode.attachChild(instancedNode); + + int extent = 30; + + for (int y = -extent; y < extent; y++) { + for (int x = -extent; x < extent; x++) { + Geometry instance = createInstance(x, y); + + float height = (smoothstep(0, 1, FastMath.nextRandomFloat()) * 2.5f) - 1.25f; + instance.setUserData("height", height); + instance.setUserData("dir", 1f); + + instancedNode.attachChild(instance); + } + } + + if (INSTANCING) { + ((InstancedNode)instancedNode).instance(); + } + + //instancedNode = (InstancedNode) instancedNode.clone(); + //instancedNode.move(0, 5, 0); + //rootNode.attachChild(instancedNode); + + cam.setLocation(new Vector3f(38.373516f, 6.689055f, 38.482082f)); + cam.setRotation(new Quaternion(-0.04004206f, 0.918326f, -0.096310444f, -0.38183528f)); + flyCam.setMoveSpeed(15); + flyCam.setEnabled(false); + } + + private float smoothstep(float edge0, float edge1, float x) { + // Scale, bias and saturate x to 0..1 range + x = FastMath.clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + // Evaluate polynomial + return x * x * (3 - 2 * x); + } + + + @Override + public void simpleUpdate(float tpf) { + time += tpf; + + if (time > 1f) { + time = 0f; + + for (Spatial instance : instancedNode.getChildren()) { + if (!(instance instanceof InstancedGeometry)) { + Geometry geom = (Geometry) instance; + geom.setMaterial(materials[FastMath.nextRandomInt(0, materials.length - 1)]); + + Mesh mesh; + if (FastMath.nextRandomInt(0, 1) == 1) mesh = mesh2; + else mesh = mesh1; + geom.setMesh(mesh); + } + } + } + + for (Spatial child : instancedNode.getChildren()) { + if (!(child instanceof InstancedGeometry)) { + float val = ((Float)child.getUserData("height")).floatValue(); + float dir = ((Float)child.getUserData("dir")).floatValue(); + + val += (dir + ((FastMath.nextRandomFloat() * 0.5f) - 0.25f)) * tpf; + + if (val > 1f) { + val = 1f; + dir = -dir; + } else if (val < 0f) { + val = 0f; + dir = -dir; + } + + Vector3f translation = child.getLocalTranslation(); + translation.y = (smoothstep(0, 1, val) * 2.5f) - 1.25f; + + child.setUserData("height", val); + child.setUserData("dir", dir); + + child.setLocalTranslation(translation); + } + } + } +} diff --git a/JmeTests/src/jme3test/scene/instancing/TestInstanceNodeWithLight.java b/JmeTests/src/jme3test/scene/instancing/TestInstanceNodeWithLight.java new file mode 100644 index 0000000..29f8530 --- /dev/null +++ b/JmeTests/src/jme3test/scene/instancing/TestInstanceNodeWithLight.java @@ -0,0 +1,62 @@ +package jme3test.scene.instancing; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.instancing.InstancedNode; +import com.jme3.scene.shape.Box; + +public class TestInstanceNodeWithLight extends SimpleApplication { + // Try to test with different offset + private static float offset = 12; + + public static void main(String[] args) { + TestInstanceNodeWithLight app = new TestInstanceNodeWithLight(); + app.start(); + } + + Geometry box; + PointLight pointLight; + + @Override + public void simpleInitApp() { + InstancedNode instancedNode = new InstancedNode("testInstancedNode"); + rootNode.attachChild(instancedNode); + + box = new Geometry("Box", new Box(0.5f, 0.5f, 0.5f)); + Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + material.setBoolean("UseInstancing", true); + material.setColor("Diffuse", ColorRGBA.Red); + material.setBoolean("UseMaterialColors", true); + box.setMaterial(material); + + instancedNode.attachChild(box); + instancedNode.instance(); + + pointLight = new PointLight(); + pointLight.setColor(ColorRGBA.White); + pointLight.setRadius(10f); + rootNode.addLight(pointLight); + + box.setLocalTranslation(new Vector3f(offset, 0, 0)); + pointLight.setPosition(new Vector3f(offset - 3f, 0, 0)); + + cam.setLocation(new Vector3f(offset - 5f, 0, 0)); + cam.lookAtDirection(Vector3f.UNIT_X, Vector3f.UNIT_Y); + } + + @Override + public void simpleUpdate(float tpf) { + offset += tpf; + + System.err.println(offset); + box.setLocalTranslation(new Vector3f(offset, 0, 0)); + pointLight.setPosition(new Vector3f(offset - 3f, 0, 0)); + + cam.setLocation(new Vector3f(offset - 5f, 0, 0)); + cam.lookAtDirection(Vector3f.UNIT_X, Vector3f.UNIT_Y); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/stress/TestBatchLod.java b/JmeTests/src/jme3test/stress/TestBatchLod.java new file mode 100644 index 0000000..08ef772 --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestBatchLod.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.stress; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.LodControl; +import jme3tools.optimize.GeometryBatchFactory; + +public class TestBatchLod extends SimpleApplication { + + private boolean lod = false; + + public static void main(String[] args) { + TestBatchLod app = new TestBatchLod(); + app.start(); + } + + public void simpleInitApp() { +// inputManager.registerKeyBinding("USELOD", KeyInput.KEY_L); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + + Node teapotNode = (Node) assetManager.loadModel("Models/Teapot/Teapot.mesh.xml"); + Geometry teapot = (Geometry) teapotNode.getChild(0); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 16f); + mat.setBoolean("VertexLighting", true); + teapot.setMaterial(mat); + + // show normals as material + //Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + flyCam.setMoveSpeed(5); + for (int y = -5; y < 5; y++) { + for (int x = -5; x < 5; x++) { + Geometry clonePot = teapot.clone(); + + //clonePot.setMaterial(mat); + clonePot.setLocalTranslation(x * .5f, 0, y * .5f); + clonePot.setLocalScale(.15f); + clonePot.setMaterial(mat); + rootNode.attachChild(clonePot); + } + } + GeometryBatchFactory.optimize(rootNode, true); + LodControl control = new LodControl(); + rootNode.getChild(0).addControl(control); + cam.setLocation(new Vector3f(-1.0748308f, 1.35778f, -1.5380064f)); + cam.setRotation(new Quaternion(0.18343268f, 0.34531063f, -0.069015436f, 0.9177962f)); + + } +} diff --git a/JmeTests/src/jme3test/stress/TestLeakingGL.java b/JmeTests/src/jme3test/stress/TestLeakingGL.java new file mode 100644 index 0000000..bd2bd48 --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestLeakingGL.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.stress; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial.CullHint; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.NativeObjectManager; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Generates 400 new meshes every frame then leaks them. + * Notice how memory usage stays constant and OpenGL objects + * are properly destroyed. + */ +public class TestLeakingGL extends SimpleApplication { + + private Material solidColor; + private Sphere original; + + public static void main(String[] args){ + TestLeakingGL app = new TestLeakingGL(); + app.start(); + } + + public void simpleInitApp() { + original = new Sphere(4, 4, 1); + original.setStatic(); + //original.setInterleaved(); + + // this will make sure all spheres are rendered always + rootNode.setCullHint(CullHint.Never); + solidColor = assetManager.loadMaterial("Common/Materials/RedColor.j3m"); + cam.setLocation(new Vector3f(0, 5, 0)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + + Logger.getLogger(Node.class.getName()).setLevel(Level.WARNING); + Logger.getLogger(NativeObjectManager.class.getName()).setLevel(Level.WARNING); + } + + @Override + public void simpleUpdate(float tpf){ + rootNode.detachAllChildren(); + for (int y = -15; y < 15; y++){ + for (int x = -15; x < 15; x++){ + Mesh sphMesh = original.deepClone(); + Geometry sphere = new Geometry("sphere", sphMesh); + + sphere.setMaterial(solidColor); + sphere.setLocalTranslation(x * 1.5f, 0, y * 1.5f); + rootNode.attachChild(sphere); + } + } + } +} diff --git a/JmeTests/src/jme3test/stress/TestLodGeneration.java b/JmeTests/src/jme3test/stress/TestLodGeneration.java new file mode 100644 index 0000000..cf8dbb6 --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestLodGeneration.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.stress; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.animation.SkeletonControl; +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.font.BitmapText; +import com.jme3.input.ChaseCamera; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import jme3tools.optimize.LodGenerator; + +public class TestLodGeneration extends SimpleApplication { + + public static void main(String[] args) { + TestLodGeneration app = new TestLodGeneration(); + app.start(); + } + boolean wireFrame = false; + float reductionvalue = 0.0f; + private int lodLevel = 0; + private Node model; + private BitmapText hudText; + private List listGeoms = new ArrayList(); + private ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(5); + private AnimChannel ch; + + public void simpleInitApp() { + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(dl); + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(0.6f)); + rootNode.addLight(al); + + // model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + model = (Node) assetManager.loadModel("Models/Jaime/Jaime.j3o"); + BoundingBox b = ((BoundingBox) model.getWorldBound()); + model.setLocalScale(1.2f / (b.getYExtent() * 2)); + // model.setLocalTranslation(0,-(b.getCenter().y - b.getYExtent())* model.getLocalScale().y, 0); + for (Spatial spatial : model.getChildren()) { + if (spatial instanceof Geometry) { + listGeoms.add((Geometry) spatial); + } + } + ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); + model.addControl(chaseCam); + chaseCam.setLookAtOffset(b.getCenter()); + chaseCam.setDefaultDistance(5); + chaseCam.setMinVerticalRotation(-FastMath.HALF_PI + 0.01f); + chaseCam.setZoomSensitivity(0.5f); + + + +// ch = model.getControl(AnimControl.class).createChannel(); +// ch.setAnim("Wave"); + SkeletonControl c = model.getControl(SkeletonControl.class); + if (c != null) { + c.setEnabled(false); + } + + + reductionvalue = 0.80f; + lodLevel = 1; + for (final Geometry geometry : listGeoms) { + LodGenerator lodGenerator = new LodGenerator(geometry); + lodGenerator.bakeLods(LodGenerator.TriangleReductionMethod.PROPORTIONAL, reductionvalue); + geometry.setLodLevel(lodLevel); + + } + + rootNode.attachChild(model); + flyCam.setEnabled(false); + + + + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + hudText = new BitmapText(guiFont, false); + hudText.setSize(guiFont.getCharSet().getRenderedSize()); + hudText.setText(computeNbTri() + " tris"); + hudText.setLocalTranslation(cam.getWidth() / 2, hudText.getLineHeight(), 0); + guiNode.attachChild(hudText); + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + if (name.equals("plus")) { +// lodLevel++; +// for (Geometry geometry : listGeoms) { +// if (geometry.getMesh().getNumLodLevels() <= lodLevel) { +// lodLevel = 0; +// } +// geometry.setLodLevel(lodLevel); +// } +// jaimeText.setText(computeNbTri() + " tris"); + + + + reductionvalue += 0.05f; + updateLod(); + + + + } + if (name.equals("minus")) { +// lodLevel--; +// for (Geometry geometry : listGeoms) { +// if (lodLevel < 0) { +// lodLevel = geometry.getMesh().getNumLodLevels() - 1; +// } +// geometry.setLodLevel(lodLevel); +// } +// jaimeText.setText(computeNbTri() + " tris"); + + + + reductionvalue -= 0.05f; + updateLod(); + + + } + if (name.equals("wireFrame")) { + wireFrame = !wireFrame; + for (Geometry geometry : listGeoms) { + geometry.getMaterial().getAdditionalRenderState().setWireframe(wireFrame); + } + } + + } + + } + + private void updateLod() { + reductionvalue = FastMath.clamp(reductionvalue, 0.0f, 1.0f); + makeLod(LodGenerator.TriangleReductionMethod.PROPORTIONAL, reductionvalue, 1); + } + }, "plus", "minus", "wireFrame"); + + inputManager.addMapping("plus", new KeyTrigger(KeyInput.KEY_ADD)); + inputManager.addMapping("minus", new KeyTrigger(KeyInput.KEY_SUBTRACT)); + inputManager.addMapping("wireFrame", new KeyTrigger(KeyInput.KEY_SPACE)); + + + + } + + @Override + public void simpleUpdate(float tpf) { + // model.rotate(0, tpf, 0); + } + + private int computeNbTri() { + int nbTri = 0; + for (Geometry geometry : listGeoms) { + if (geometry.getMesh().getNumLodLevels() > 0) { + nbTri += geometry.getMesh().getLodLevel(lodLevel).getNumElements(); + } else { + nbTri += geometry.getMesh().getTriangleCount(); + } + } + return nbTri; + } + + @Override + public void destroy() { + super.destroy(); + exec.shutdown(); + } + + private void makeLod(final LodGenerator.TriangleReductionMethod method, final float value, final int ll) { + exec.execute(new Runnable() { + public void run() { + for (final Geometry geometry : listGeoms) { + LodGenerator lODGenerator = new LodGenerator(geometry); + final VertexBuffer[] lods = lODGenerator.computeLods(method, value); + + enqueue(new Callable() { + public Void call() throws Exception { + geometry.getMesh().setLodLevels(lods); + lodLevel = 0; + if (geometry.getMesh().getNumLodLevels() > ll) { + lodLevel = ll; + } + geometry.setLodLevel(lodLevel); + hudText.setText(computeNbTri() + " tris"); + return null; + } + }); + } + } + }); + + } +} diff --git a/JmeTests/src/jme3test/stress/TestLodStress.java b/JmeTests/src/jme3test/stress/TestLodStress.java new file mode 100644 index 0000000..21b8e9d --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestLodStress.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.stress; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.control.LodControl; + +public class TestLodStress extends SimpleApplication { + + public static void main(String[] args){ + TestLodStress app = new TestLodStress(); + app.setShowSettings(false); + app.setPauseOnLostFocus(false); + app.start(); + } + + public void simpleInitApp() { + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1,-1,-1).normalizeLocal()); + rootNode.addLight(dl); + + Node teapotNode = (Node) assetManager.loadModel("Models/Teapot/Teapot.mesh.xml"); + Geometry teapot = (Geometry) teapotNode.getChild(0); + +// Sphere sph = new Sphere(16, 16, 4); +// Geometry teapot = new Geometry("teapot", sph); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 16f); + mat.setBoolean("VertexLighting", true); + teapot.setMaterial(mat); + + // show normals as material + //Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); + + for (int y = -10; y < 10; y++){ + for (int x = -10; x < 10; x++){ + Geometry clonePot = teapot.clone(); + + //clonePot.setMaterial(mat); + clonePot.setLocalTranslation(x * .5f, 0, y * .5f); + clonePot.setLocalScale(.15f); + + LodControl control = new LodControl(); + clonePot.addControl(control); + rootNode.attachChild(clonePot); + } + } + + cam.setLocation(new Vector3f(8.378951f, 5.4324f, 8.795956f)); + cam.setRotation(new Quaternion(-0.083419204f, 0.90370524f, -0.20599906f, -0.36595422f)); + } + +} diff --git a/JmeTests/src/jme3test/stress/TestParallelTangentGeneration.java b/JmeTests/src/jme3test/stress/TestParallelTangentGeneration.java new file mode 100644 index 0000000..421589f --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestParallelTangentGeneration.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.stress; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.TangentBinormalGenerator; + +public class TestParallelTangentGeneration { + + static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + + public static void main(String[] args) { + + for (int i = 0; i < 10; i++) { + { + Node root = new Node("Root"); + for (int count = 0; count < 10; count++) { + for (int samples = 4; samples < 50; samples++) { + Geometry g = new Geometry(); + g.setMesh(new Sphere(samples, samples, 1.0f)); + root.attachChild(g); + } + } + + long start = System.currentTimeMillis(); + TangentBinormalGenerator.generate(root); + System.out.println("Serial " + (System.currentTimeMillis() - start)); + } + + { + Node root = new Node("Root"); + for (int count = 0; count < 10; count++) { + for (int samples = 4; samples < 50; samples++) { + Geometry g = new Geometry(); + g.setMesh(new Sphere(samples, samples, 1.0f)); + root.attachChild(g); + } + } + + long start = System.currentTimeMillis(); + TangentBinormalGenerator.generateParallel(root, executor); + System.out.println("Parallel " + (System.currentTimeMillis() - start)); + } + + } + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/stress/TestShaderNodesStress.java b/JmeTests/src/jme3test/stress/TestShaderNodesStress.java new file mode 100644 index 0000000..dc74d3c --- /dev/null +++ b/JmeTests/src/jme3test/stress/TestShaderNodesStress.java @@ -0,0 +1,105 @@ +package jme3test.stress; + +import com.jme3.app.BasicProfilerState; +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.profile.*; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Texture; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class TestShaderNodesStress extends SimpleApplication { + + public static void main(String[] args) { + TestShaderNodesStress app = new TestShaderNodesStress(); + app.start(); + } + + @Override + public void simpleInitApp() { + + Quad q = new Quad(1, 1); + Geometry g = new Geometry("quad", q); + g.setLocalTranslation(-500, -500, 0); + g.setLocalScale(1000); + + rootNode.attachChild(g); + cam.setLocation(new Vector3f(0.0f, 0.0f, 0.40647888f)); + cam.setRotation(new Quaternion(0.0f, 1.0f, 0.0f, 0.0f)); + + Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); + //Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + + mat.setColor("Color", ColorRGBA.Yellow); + mat.setTexture("ColorMap", tex); + g.setMaterial(mat); + //place the geoms in the transparent bucket so that they are rendered back to front for maximum overdraw + g.setQueueBucket(RenderQueue.Bucket.Transparent); + + for (int i = 0; i < 1000; i++) { + Geometry cl = g.clone(false); + cl.move(0, 0, -(i + 1)); + rootNode.attachChild(cl); + } + + flyCam.setMoveSpeed(20); + Logger.getLogger("com.jme3").setLevel(Level.WARNING); + + this.setAppProfiler(new Profiler()); + + } + + private class Profiler implements AppProfiler { + + private long startTime; + private long updateTime; + private long renderTime; + private long sum; + private int nbFrames; + + @Override + public void appStep(AppStep step) { + + switch (step) { + case BeginFrame: + startTime = System.nanoTime(); + break; + case RenderFrame: + updateTime = System.nanoTime(); + // System.err.println("Update time : " + (updateTime - startTime)); + break; + case EndFrame: + nbFrames++; + if (nbFrames >= 150) { + renderTime = System.nanoTime(); + sum += renderTime - updateTime; + System.err.println("render time : " + (renderTime - updateTime)); + System.err.println("Average render time : " + ((float)sum / (float)(nbFrames-150))); + } + break; + + } + + } + + @Override + public void vpStep(VpStep step, ViewPort vp, RenderQueue.Bucket bucket) { + + } + + @Override + public void spStep(SpStep step, String... additionalInfo) { + + } + + } +} diff --git a/JmeTests/src/jme3test/terrain/TerrainFractalGridTest.java b/JmeTests/src/jme3test/terrain/TerrainFractalGridTest.java new file mode 100644 index 0000000..0ab647d --- /dev/null +++ b/JmeTests/src/jme3test/terrain/TerrainFractalGridTest.java @@ -0,0 +1,148 @@ +package jme3test.terrain; + +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.ScreenshotAppState; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.terrain.geomipmap.TerrainGrid; +import com.jme3.terrain.geomipmap.TerrainGridLodControl; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.grid.FractalTileLoader; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.noise.ShaderUtils; +import com.jme3.terrain.noise.basis.FilteredBasis; +import com.jme3.terrain.noise.filter.IterativeFilter; +import com.jme3.terrain.noise.filter.OptimizedErode; +import com.jme3.terrain.noise.filter.PerturbFilter; +import com.jme3.terrain.noise.filter.SmoothFilter; +import com.jme3.terrain.noise.fractal.FractalSum; +import com.jme3.terrain.noise.modulator.NoiseModulator; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; + +public class TerrainFractalGridTest extends SimpleApplication { + + private Material mat_terrain; + private TerrainGrid terrain; + private float grassScale = 64; + private float dirtScale = 16; + private float rockScale = 128; + + public static void main(final String[] args) { + TerrainFractalGridTest app = new TerrainFractalGridTest(); + app.start(); + } + private CharacterControl player3; + private FractalSum base; + private PerturbFilter perturb; + private OptimizedErode therm; + private SmoothFilter smooth; + private IterativeFilter iterate; + + @Override + public void simpleInitApp() { + this.flyCam.setMoveSpeed(100f); + ScreenshotAppState state = new ScreenshotAppState(); + this.stateManager.attach(state); + + // TERRAIN TEXTURE material + this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); + + // Parameters to material: + // regionXColorMap: X = 1..4 the texture that should be appliad to state X + // regionX: a Vector3f containing the following information: + // regionX.x: the start height of the region + // regionX.y: the end height of the region + // regionX.z: the texture scale for the region + // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) + // slopeColorMap: the texture to be used for cliffs, and steep mountain sites + // slopeTileFactor: the texture scale for slopes + // terrainSize: the total size of the terrain (used for scaling the texture) + // GRASS texture + Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + this.mat_terrain.setTexture("region1ColorMap", grass); + this.mat_terrain.setVector3("region1", new Vector3f(15, 200, this.grassScale)); + + // DIRT texture + Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + this.mat_terrain.setTexture("region2ColorMap", dirt); + this.mat_terrain.setVector3("region2", new Vector3f(0, 20, this.dirtScale)); + + // ROCK texture + Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + rock.setWrap(WrapMode.Repeat); + this.mat_terrain.setTexture("region3ColorMap", rock); + this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); + + this.mat_terrain.setTexture("region4ColorMap", rock); + this.mat_terrain.setVector3("region4", new Vector3f(198, 260, this.rockScale)); + + this.mat_terrain.setTexture("slopeColorMap", rock); + this.mat_terrain.setFloat("slopeTileFactor", 32); + + this.mat_terrain.setFloat("terrainSize", 513); + + this.base = new FractalSum(); + this.base.setRoughness(0.7f); + this.base.setFrequency(1.0f); + this.base.setAmplitude(1.0f); + this.base.setLacunarity(2.12f); + this.base.setOctaves(8); + this.base.setScale(0.02125f); + this.base.addModulator(new NoiseModulator() { + + @Override + public float value(float... in) { + return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1); + } + }); + + FilteredBasis ground = new FilteredBasis(this.base); + + this.perturb = new PerturbFilter(); + this.perturb.setMagnitude(0.119f); + + this.therm = new OptimizedErode(); + this.therm.setRadius(5); + this.therm.setTalus(0.011f); + + this.smooth = new SmoothFilter(); + this.smooth.setRadius(1); + this.smooth.setEffect(0.7f); + + this.iterate = new IterativeFilter(); + this.iterate.addPreFilter(this.perturb); + this.iterate.addPostFilter(this.smooth); + this.iterate.setFilter(this.therm); + this.iterate.setIterations(1); + + ground.addPreFilter(this.iterate); + + this.terrain = new TerrainGrid("terrain", 33, 129, new FractalTileLoader(ground, 256f)); + + this.terrain.setMaterial(this.mat_terrain); + this.terrain.setLocalTranslation(0, 0, 0); + this.terrain.setLocalScale(2f, 1f, 2f); + this.rootNode.attachChild(this.terrain); + + TerrainLodControl control = new TerrainGridLodControl(this.terrain, this.getCamera()); + control.setLodCalculator(new DistanceLodCalculator(33, 2.7f)); // patch size, and a multiplier + this.terrain.addControl(control); + + + + this.getCamera().setLocation(new Vector3f(0, 300, 0)); + + this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); + + + } + + @Override + public void simpleUpdate(final float tpf) { + } +} diff --git a/JmeTests/src/jme3test/terrain/TerrainGridAlphaMapTest.java b/JmeTests/src/jme3test/terrain/TerrainGridAlphaMapTest.java new file mode 100644 index 0000000..ef0f6c1 --- /dev/null +++ b/JmeTests/src/jme3test/terrain/TerrainGridAlphaMapTest.java @@ -0,0 +1,357 @@ +package jme3test.terrain; + +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.ScreenshotAppState; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.bullet.BulletAppState; +import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; +import com.jme3.terrain.geomipmap.TerrainGrid; +import com.jme3.terrain.geomipmap.TerrainGridListener; +import com.jme3.terrain.geomipmap.TerrainGridLodControl; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.grid.FractalTileLoader; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.noise.ShaderUtils; +import com.jme3.terrain.noise.basis.FilteredBasis; +import com.jme3.terrain.noise.filter.IterativeFilter; +import com.jme3.terrain.noise.filter.OptimizedErode; +import com.jme3.terrain.noise.filter.PerturbFilter; +import com.jme3.terrain.noise.filter.SmoothFilter; +import com.jme3.terrain.noise.fractal.FractalSum; +import com.jme3.terrain.noise.modulator.NoiseModulator; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import java.io.File; + +public class TerrainGridAlphaMapTest extends SimpleApplication { + + private TerrainGrid terrain; + private float grassScale = 64; + private float dirtScale = 16; + private float rockScale = 128; + private boolean usePhysics = false; + + public static void main(final String[] args) { + TerrainGridAlphaMapTest app = new TerrainGridAlphaMapTest(); + app.start(); + } + private CharacterControl player3; + private FractalSum base; + private PerturbFilter perturb; + private OptimizedErode therm; + private SmoothFilter smooth; + private IterativeFilter iterate; + private Material material; + private Material matWire; + + @Override + public void simpleInitApp() { + DirectionalLight sun = new DirectionalLight(); + sun.setColor(ColorRGBA.White); + sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(sun); + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.White.mult(1.3f)); + rootNode.addLight(al); + + File file = new File("TerrainGridTestData.zip"); + if (!file.exists()) { + assetManager.registerLocator("https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/TerrainGridTestData.zip", HttpZipLocator.class); + } else { + assetManager.registerLocator("TerrainGridTestData.zip", ZipLocator.class); + } + + this.flyCam.setMoveSpeed(100f); + ScreenshotAppState state = new ScreenshotAppState(); + this.stateManager.attach(state); + + // TERRAIN TEXTURE material + material = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + material.setBoolean("useTriPlanarMapping", false); + //material.setBoolean("isTerrainGrid", true); + material.setFloat("Shininess", 0.0f); + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + material.setTexture("DiffuseMap", grass); + material.setFloat("DiffuseMap_0_scale", grassScale); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + material.setTexture("DiffuseMap_1", dirt); + material.setFloat("DiffuseMap_1_scale", dirtScale); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + material.setTexture("DiffuseMap_2", rock); + material.setFloat("DiffuseMap_2_scale", rockScale); + + // WIREFRAME material + matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWire.getAdditionalRenderState().setWireframe(true); + matWire.setColor("Color", ColorRGBA.Green); + + this.base = new FractalSum(); + this.base.setRoughness(0.7f); + this.base.setFrequency(1.0f); + this.base.setAmplitude(1.0f); + this.base.setLacunarity(2.12f); + this.base.setOctaves(8); + this.base.setScale(0.02125f); + this.base.addModulator(new NoiseModulator() { + + @Override + public float value(float... in) { + return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1); + } + }); + + FilteredBasis ground = new FilteredBasis(this.base); + + this.perturb = new PerturbFilter(); + this.perturb.setMagnitude(0.119f); + + this.therm = new OptimizedErode(); + this.therm.setRadius(5); + this.therm.setTalus(0.011f); + + this.smooth = new SmoothFilter(); + this.smooth.setRadius(1); + this.smooth.setEffect(0.7f); + + this.iterate = new IterativeFilter(); + this.iterate.addPreFilter(this.perturb); + this.iterate.addPostFilter(this.smooth); + this.iterate.setFilter(this.therm); + this.iterate.setIterations(1); + + ground.addPreFilter(this.iterate); + + this.terrain = new TerrainGrid("terrain", 33, 257, new FractalTileLoader(ground, 256)); + this.terrain.setMaterial(this.material); + + this.terrain.setLocalTranslation(0, 0, 0); + this.terrain.setLocalScale(2f, 1f, 2f); + this.rootNode.attachChild(this.terrain); + + TerrainLodControl control = new TerrainGridLodControl(this.terrain, this.getCamera()); + control.setLodCalculator( new DistanceLodCalculator(33, 2.7f) ); // patch size, and a multiplier + this.terrain.addControl(control); + + final BulletAppState bulletAppState = new BulletAppState(); + stateManager.attach(bulletAppState); + + + this.getCamera().setLocation(new Vector3f(0, 256, 0)); + + this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); + + if (usePhysics) { + CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); + player3 = new CharacterControl(capsuleShape, 0.5f); + player3.setJumpSpeed(20); + player3.setFallSpeed(10); + player3.setGravity(10); + + player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z)); + + bulletAppState.getPhysicsSpace().add(player3); + + } + terrain.addListener(new TerrainGridListener() { + + public void gridMoved(Vector3f newCenter) { + } + + public void tileAttached(Vector3f cell, TerrainQuad quad) { + Texture alpha = null; + try { + alpha = assetManager.loadTexture("TerrainAlphaTest/alpha_" + (int)cell.x+ "_" + (int)cell.z + ".png"); + } catch (Exception e) { + alpha = assetManager.loadTexture("TerrainAlphaTest/alpha_default.png"); + } + quad.getMaterial().setTexture("AlphaMap", alpha); + if (usePhysics) { + quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()), 0)); + bulletAppState.getPhysicsSpace().add(quad); + } + updateMarkerElevations(); + } + + public void tileDetached(Vector3f cell, TerrainQuad quad) { + if (usePhysics) { + if (quad.getControl(RigidBodyControl.class) != null) { + bulletAppState.getPhysicsSpace().remove(quad); + quad.removeControl(RigidBodyControl.class); + } + } + updateMarkerElevations(); + } + }); + + this.initKeys(); + + markers = new Node(); + rootNode.attachChild(markers); + createMarkerPoints(1); + } + + Node markers; + + + private void createMarkerPoints(float count) { + Node center = createAxisMarker(10); + markers.attachChild(center); + + float xS = (count-1)*terrain.getTerrainSize() - (terrain.getTerrainSize()/2); + float zS = (count-1)*terrain.getTerrainSize() - (terrain.getTerrainSize()/2); + float xSi = xS; + float zSi = zS; + for (int x=0; x 0) { + CollisionResult hit = results.getClosestCollision(); + if (collisionMarker == null) { + createCollisionMarker(); + } + Vector2f loc = new Vector2f(hit.getContactPoint().x, hit.getContactPoint().z); + float height = terrain.getHeight(loc); + System.out.println("collide " + hit.getContactPoint() + ", height: " + height + ", distance: " + hit.getDistance()); + collisionMarker.setLocalTranslation(new Vector3f(hit.getContactPoint().x, height, hit.getContactPoint().z)); + } + } else if (binding.equals("cameraDown") && !keyPressed) { + getCamera().lookAtDirection(new Vector3f(0, -1, 0), Vector3f.UNIT_Y); + } else if (binding.equals("Lefts") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(-0.5f, 0, 0); + testCollision(oldLoc); + } else if (binding.equals("Rights") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(0.5f, 0, 0); + testCollision(oldLoc); + } else if (binding.equals("Forwards") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(0, 0, 0.5f); + testCollision(oldLoc); + } else if (binding.equals("Backs") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(0, 0, -0.5f); + testCollision(oldLoc); + } else if (binding.equals("Ups") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(0, 0.5f, 0); + testCollision(oldLoc); + } else if (binding.equals("Downs") && !keyPressed) { + Vector3f oldLoc = selectedCollisionObject.getLocalTranslation().clone(); + selectedCollisionObject.move(0, -0.5f, 0); + testCollision(oldLoc); + } + + } + }; + + private void testCollision(Vector3f oldLoc) { + if (terrain.collideWith(selectedCollisionObject.getWorldBound(), new CollisionResults()) > 0) { + selectedCollisionObject.setLocalTranslation(oldLoc); + } + } +} diff --git a/JmeTests/src/jme3test/terrain/TerrainTestModifyHeight.java b/JmeTests/src/jme3test/terrain/TerrainTestModifyHeight.java new file mode 100644 index 0000000..b687615 --- /dev/null +++ b/JmeTests/src/jme3test/terrain/TerrainTestModifyHeight.java @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.terrain; + +import com.jme3.app.SimpleApplication; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Ray; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.shape.Sphere; +import com.jme3.terrain.geomipmap.TerrainGrid; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.grid.FractalTileLoader; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.terrain.noise.ShaderUtils; +import com.jme3.terrain.noise.basis.FilteredBasis; +import com.jme3.terrain.noise.filter.IterativeFilter; +import com.jme3.terrain.noise.filter.OptimizedErode; +import com.jme3.terrain.noise.filter.PerturbFilter; +import com.jme3.terrain.noise.filter.SmoothFilter; +import com.jme3.terrain.noise.fractal.FractalSum; +import com.jme3.terrain.noise.modulator.NoiseModulator; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Brent Owens + */ +public class TerrainTestModifyHeight extends SimpleApplication { + + private TerrainQuad terrain; + Material matTerrain; + Material matWire; + boolean wireframe = true; + boolean triPlanar = false; + boolean wardiso = false; + boolean minnaert = false; + protected BitmapText hintText; + private float grassScale = 64; + private float dirtScale = 16; + private float rockScale = 128; + + private boolean raiseTerrain = false; + private boolean lowerTerrain = false; + + private Geometry marker; + private Geometry markerNormal; + + public static void main(String[] args) { + TerrainTestModifyHeight app = new TerrainTestModifyHeight(); + app.start(); + } + + @Override + public void simpleUpdate(float tpf){ + Vector3f intersection = getWorldIntersection(); + updateHintText(intersection); + + if (raiseTerrain){ + + if (intersection != null) { + adjustHeight(intersection, 64, tpf * 60); + } + }else if (lowerTerrain){ + if (intersection != null) { + adjustHeight(intersection, 64, -tpf * 60); + } + } + + if (terrain != null && intersection != null) { + float h = terrain.getHeight(new Vector2f(intersection.x, intersection.z)); + Vector3f tl = terrain.getWorldTranslation(); + marker.setLocalTranslation(tl.add(new Vector3f(intersection.x, h, intersection.z)) ); + markerNormal.setLocalTranslation(tl.add(new Vector3f(intersection.x, h, intersection.z)) ); + + Vector3f normal = terrain.getNormal(new Vector2f(intersection.x, intersection.z)); + ((Arrow)markerNormal.getMesh()).setArrowExtent(normal); + } + } + + @Override + public void simpleInitApp() { + loadHintText(); + initCrossHairs(); + setupKeys(); + + createMarker(); + + // WIREFRAME material + matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWire.getAdditionalRenderState().setWireframe(true); + matWire.setColor("Color", ColorRGBA.Green); + + createTerrain(); + //createTerrainGrid(); + + DirectionalLight light = new DirectionalLight(); + light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); + rootNode.addLight(light); + + AmbientLight ambLight = new AmbientLight(); + ambLight.setColor(new ColorRGBA(1f, 1f, 0.8f, 0.2f)); + rootNode.addLight(ambLight); + + cam.setLocation(new Vector3f(0, 256, 0)); + cam.lookAtDirection(new Vector3f(0, -1f, 0).normalizeLocal(), Vector3f.UNIT_X); + } + + public void loadHintText() { + hintText = new BitmapText(guiFont, false); + hintText.setLocalTranslation(0, getCamera().getHeight(), 0); + hintText.setText("Hit 1 to raise terrain, hit 2 to lower terrain"); + guiNode.attachChild(hintText); + } + + public void updateHintText(Vector3f target) { + int x = (int) getCamera().getLocation().x; + int y = (int) getCamera().getLocation().y; + int z = (int) getCamera().getLocation().z; + String targetText = ""; + if (target!= null) + targetText = " intersect: "+target.toString(); + hintText.setText("Press left mouse button to raise terrain, press right mouse button to lower terrain. " + x + "," + y + "," + z+targetText); + } + + protected void initCrossHairs() { + BitmapText ch = new BitmapText(guiFont, false); + ch.setSize(guiFont.getCharSet().getRenderedSize() * 2); + ch.setText("+"); // crosshairs + ch.setLocalTranslation( // center + settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2, + settings.getHeight() / 2 + ch.getLineHeight() / 2, 0); + guiNode.attachChild(ch); + } + + private void setupKeys() { + flyCam.setMoveSpeed(100); + inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addListener(actionListener, "wireframe"); + inputManager.addMapping("Raise", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(actionListener, "Raise"); + inputManager.addMapping("Lower", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); + inputManager.addListener(actionListener, "Lower"); + } + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean pressed, float tpf) { + if (name.equals("wireframe") && !pressed) { + wireframe = !wireframe; + if (!wireframe) { + terrain.setMaterial(matWire); + } else { + terrain.setMaterial(matTerrain); + } + } else if (name.equals("Raise")) { + raiseTerrain = pressed; + } else if (name.equals("Lower")) { + lowerTerrain = pressed; + } + } + }; + + private void adjustHeight(Vector3f loc, float radius, float height) { + + // offset it by radius because in the loop we iterate through 2 radii + int radiusStepsX = (int) (radius / terrain.getLocalScale().x); + int radiusStepsZ = (int) (radius / terrain.getLocalScale().z); + + float xStepAmount = terrain.getLocalScale().x; + float zStepAmount = terrain.getLocalScale().z; + long start = System.currentTimeMillis(); + List locs = new ArrayList(); + List heights = new ArrayList(); + + for (int z = -radiusStepsZ; z < radiusStepsZ; z++) { + for (int x = -radiusStepsX; x < radiusStepsX; x++) { + + float locX = loc.x + (x * xStepAmount); + float locZ = loc.z + (z * zStepAmount); + + if (isInRadius(locX - loc.x, locZ - loc.z, radius)) { + // see if it is in the radius of the tool + float h = calculateHeight(radius, height, locX - loc.x, locZ - loc.z); + locs.add(new Vector2f(locX, locZ)); + heights.add(h); + } + } + } + + terrain.adjustHeight(locs, heights); + //System.out.println("Modified "+locs.size()+" points, took: " + (System.currentTimeMillis() - start)+" ms"); + terrain.updateModelBound(); + } + + private boolean isInRadius(float x, float y, float radius) { + Vector2f point = new Vector2f(x, y); + // return true if the distance is less than equal to the radius + return point.length() <= radius; + } + + private float calculateHeight(float radius, float heightFactor, float x, float z) { + // find percentage for each 'unit' in radius + Vector2f point = new Vector2f(x, z); + float val = point.length() / radius; + val = 1 - val; + if (val <= 0) { + val = 0; + } + return heightFactor * val; + } + + private Vector3f getWorldIntersection() { + Vector3f origin = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.0f); + Vector3f direction = cam.getWorldCoordinates(new Vector2f(settings.getWidth() / 2, settings.getHeight() / 2), 0.3f); + direction.subtractLocal(origin).normalizeLocal(); + + Ray ray = new Ray(origin, direction); + CollisionResults results = new CollisionResults(); + int numCollisions = terrain.collideWith(ray, results); + if (numCollisions > 0) { + CollisionResult hit = results.getClosestCollision(); + return hit.getContactPoint(); + } + return null; + } + + private void createTerrain() { + // First, we load up our textures and the heightmap texture for the terrain + + // TERRAIN TEXTURE material + matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matTerrain.setBoolean("useTriPlanarMapping", false); + matTerrain.setBoolean("WardIso", true); + matTerrain.setFloat("Shininess", 0); + + // ALPHA map (for splat textures) + matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap", grass); + matTerrain.setFloat("DiffuseMap_0_scale", grassScale); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_1", dirt); + matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_2", rock); + matTerrain.setFloat("DiffuseMap_2_scale", rockScale); + + // HEIGHTMAP image (for the terrain heightmap) + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.5f); + heightmap.load(); + heightmap.smooth(0.9f, 1); + + } catch (Exception e) { + e.printStackTrace(); + } + + // CREATE THE TERRAIN + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + TerrainLodControl control = new TerrainLodControl(terrain, getCamera()); + control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier + terrain.addControl(control); + terrain.setMaterial(matTerrain); + terrain.setLocalTranslation(0, -100, 0); + terrain.setLocalScale(2.5f, 0.5f, 2.5f); + rootNode.attachChild(terrain); + } + + private void createTerrainGrid() { + + // TERRAIN TEXTURE material + matTerrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); + + // Parameters to material: + // regionXColorMap: X = 1..4 the texture that should be appliad to state X + // regionX: a Vector3f containing the following information: + // regionX.x: the start height of the region + // regionX.y: the end height of the region + // regionX.z: the texture scale for the region + // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) + // slopeColorMap: the texture to be used for cliffs, and steep mountain sites + // slopeTileFactor: the texture scale for slopes + // terrainSize: the total size of the terrain (used for scaling the texture) + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region1ColorMap", grass); + matTerrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region2ColorMap", dirt); + matTerrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("region3ColorMap", rock); + matTerrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); + + matTerrain.setTexture("region4ColorMap", rock); + matTerrain.setVector3("region4", new Vector3f(198, 260, this.rockScale)); + + matTerrain.setTexture("slopeColorMap", rock); + matTerrain.setFloat("slopeTileFactor", 32); + + matTerrain.setFloat("terrainSize", 513); + + FractalSum base = new FractalSum(); + base.setRoughness(0.7f); + base.setFrequency(1.0f); + base.setAmplitude(1.0f); + base.setLacunarity(2.12f); + base.setOctaves(8); + base.setScale(0.02125f); + base.addModulator(new NoiseModulator() { + @Override + public float value(float... in) { + return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1); + } + }); + + FilteredBasis ground = new FilteredBasis(base); + + PerturbFilter perturb = new PerturbFilter(); + perturb.setMagnitude(0.119f); + + OptimizedErode therm = new OptimizedErode(); + therm.setRadius(5); + therm.setTalus(0.011f); + + SmoothFilter smooth = new SmoothFilter(); + smooth.setRadius(1); + smooth.setEffect(0.7f); + + IterativeFilter iterate = new IterativeFilter(); + iterate.addPreFilter(perturb); + iterate.addPostFilter(smooth); + iterate.setFilter(therm); + iterate.setIterations(1); + + ground.addPreFilter(iterate); + + this.terrain = new TerrainGrid("terrain", 65, 257, new FractalTileLoader(ground, 256f)); + + + terrain.setMaterial(matTerrain); + terrain.setLocalTranslation(0, 0, 0); + terrain.setLocalScale(2f, 1f, 2f); + + rootNode.attachChild(this.terrain); + + TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera()); + this.terrain.addControl(control); + } + + private void createMarker() { + // collision marker + Sphere sphere = new Sphere(8, 8, 0.5f); + marker = new Geometry("Marker"); + marker.setMesh(sphere); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA(251f/255f, 130f/255f, 0f, 0.6f)); + mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + + marker.setMaterial(mat); + rootNode.attachChild(marker); + + + // surface normal marker + Arrow arrow = new Arrow(new Vector3f(0,1,0)); + markerNormal = new Geometry("MarkerNormal"); + markerNormal.setMesh(arrow); + markerNormal.setMaterial(mat); + rootNode.attachChild(markerNormal); + } +} diff --git a/JmeTests/src/jme3test/terrain/TerrainTestReadWrite.java b/JmeTests/src/jme3test/terrain/TerrainTestReadWrite.java new file mode 100644 index 0000000..b6bba1c --- /dev/null +++ b/JmeTests/src/jme3test/terrain/TerrainTestReadWrite.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.terrain; + +import com.jme3.app.SimpleApplication; +import com.jme3.export.Savable; +import com.jme3.export.binary.BinaryExporter; +import com.jme3.export.binary.BinaryImporter; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.terrain.Terrain; +import com.jme3.terrain.geomipmap.TerrainLodControl; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Saves and loads terrain. + * + * @author Brent Owens + */ +public class TerrainTestReadWrite extends SimpleApplication { + + private Terrain terrain; + protected BitmapText hintText; + private float grassScale = 64; + private float dirtScale = 16; + private float rockScale = 128; + private Material matTerrain; + private Material matWire; + + public static void main(String[] args) { + TerrainTestReadWrite app = new TerrainTestReadWrite(); + app.start(); + //testHeightmapBuilding(); + } + + @Override + public void initialize() { + super.initialize(); + + loadHintText(); + } + + @Override + public void simpleInitApp() { + + + createControls(); + createMap(); + } + + private void createMap() { + matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matTerrain.setBoolean("useTriPlanarMapping", false); + matTerrain.setBoolean("WardIso", true); + + // ALPHA map (for splat textures) + matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + + // HEIGHTMAP image (for the terrain heightmap) + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap", grass); + matTerrain.setFloat("DiffuseMap_0_scale", grassScale); + + + // DIRT texture + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_1", dirt); + matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); + + // ROCK texture + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap_2", rock); + matTerrain.setFloat("DiffuseMap_2_scale", rockScale); + + + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matTerrain.setTexture("NormalMap", normalMap0); + matTerrain.setTexture("NormalMap_1", normalMap2); + matTerrain.setTexture("NormalMap_2", normalMap2); + + matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWire.getAdditionalRenderState().setWireframe(true); + matWire.setColor("Color", ColorRGBA.Green); + + + // CREATE HEIGHTMAP + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 1f); + heightmap.load(); + + } catch (Exception e) { + e.printStackTrace(); + } + + if (new File("terrainsave.jme").exists()) { + loadTerrain(); + } else { + // create the terrain as normal, and give it a control for LOD management + TerrainQuad terrainQuad = new TerrainQuad("terrain", 65, 129, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations + TerrainLodControl control = new TerrainLodControl(terrainQuad, getCamera()); + control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier + terrainQuad.addControl(control); + terrainQuad.setMaterial(matTerrain); + terrainQuad.setLocalTranslation(0, -100, 0); + terrainQuad.setLocalScale(4f, 0.25f, 4f); + rootNode.attachChild(terrainQuad); + + this.terrain = terrainQuad; + } + + DirectionalLight light = new DirectionalLight(); + light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); + rootNode.addLight(light); + } + + /** + * Create the save and load actions and add them to the input listener + */ + private void createControls() { + flyCam.setMoveSpeed(50); + cam.setLocation(new Vector3f(0, 100, 0)); + + inputManager.addMapping("save", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addListener(saveActionListener, "save"); + + inputManager.addMapping("load", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addListener(loadActionListener, "load"); + + inputManager.addMapping("clone", new KeyTrigger(KeyInput.KEY_C)); + inputManager.addListener(cloneActionListener, "clone"); + } + + public void loadHintText() { + hintText = new BitmapText(guiFont, false); + hintText.setSize(guiFont.getCharSet().getRenderedSize()); + hintText.setLocalTranslation(0, getCamera().getHeight(), 0); + hintText.setText("Hit T to save, and Y to load"); + guiNode.attachChild(hintText); + } + private ActionListener saveActionListener = new ActionListener() { + + public void onAction(String name, boolean pressed, float tpf) { + if (name.equals("save") && !pressed) { + + FileOutputStream fos = null; + try { + long start = System.currentTimeMillis(); + fos = new FileOutputStream(new File("terrainsave.jme")); + + // we just use the exporter and pass in the terrain + BinaryExporter.getInstance().save((Savable)terrain, new BufferedOutputStream(fos)); + + fos.flush(); + float duration = (System.currentTimeMillis() - start) / 1000.0f; + System.out.println("Save took " + duration + " seconds"); + } catch (IOException ex) { + Logger.getLogger(TerrainTestReadWrite.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + Logger.getLogger(TerrainTestReadWrite.class.getName()).log(Level.SEVERE, null, e); + } + } + } + } + }; + + private void loadTerrain() { + FileInputStream fis = null; + try { + long start = System.currentTimeMillis(); + // remove the existing terrain and detach it from the root node. + if (terrain != null) { + Node existingTerrain = (Node)terrain; + existingTerrain.removeFromParent(); + existingTerrain.removeControl(TerrainLodControl.class); + existingTerrain.detachAllChildren(); + terrain = null; + } + + // import the saved terrain, and attach it back to the root node + File f = new File("terrainsave.jme"); + fis = new FileInputStream(f); + BinaryImporter imp = BinaryImporter.getInstance(); + imp.setAssetManager(assetManager); + terrain = (TerrainQuad) imp.load(new BufferedInputStream(fis)); + rootNode.attachChild((Node)terrain); + + float duration = (System.currentTimeMillis() - start) / 1000.0f; + System.out.println("Load took " + duration + " seconds"); + + // now we have to add back the camera to the LOD control + TerrainLodControl lodControl = ((Node)terrain).getControl(TerrainLodControl.class); + if (lodControl != null) + lodControl.setCamera(getCamera()); + + } catch (IOException ex) { + Logger.getLogger(TerrainTestReadWrite.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if (fis != null) { + fis.close(); + } + } catch (IOException ex) { + Logger.getLogger(TerrainTestReadWrite.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + private ActionListener loadActionListener = new ActionListener() { + + public void onAction(String name, boolean pressed, float tpf) { + if (name.equals("load") && !pressed) { + loadTerrain(); + } + } + }; + private ActionListener cloneActionListener = new ActionListener() { + + public void onAction(String name, boolean pressed, float tpf) { + if (name.equals("clone") && !pressed) { + + Terrain clone = (Terrain) ((Node)terrain).clone(); + ((Node)terrain).removeFromParent(); + terrain = clone; + getRootNode().attachChild((Node)terrain); + } + } + }; + + // no junit tests, so this has to be hand-tested: + private static void testHeightmapBuilding() { + int s = 9; + int b = 3; + float[] hm = new float[s * s]; + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + hm[(i * s) + j] = i * j; + } + } + + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + System.out.print(hm[i * s + j] + " "); + } + System.out.println(""); + } + + TerrainQuad terrain = new TerrainQuad("terrain", b, s, hm); + float[] hm2 = terrain.getHeightMap(); + boolean failed = false; + for (int i = 0; i < s * s; i++) { + if (hm[i] != hm2[i]) { + failed = true; + } + } + + System.out.println(""); + if (failed) { + System.out.println("Terrain heightmap building FAILED!!!"); + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + System.out.print(hm2[i * s + j] + " "); + } + System.out.println(""); + } + } else { + System.out.println("Terrain heightmap building PASSED"); + } + } +} diff --git a/JmeTests/src/jme3test/terrain/TerrainTestTile.java b/JmeTests/src/jme3test/terrain/TerrainTestTile.java new file mode 100644 index 0000000..4e093e8 --- /dev/null +++ b/JmeTests/src/jme3test/terrain/TerrainTestTile.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.terrain; + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Sphere; +import com.jme3.terrain.ProgressMonitor; +import com.jme3.terrain.Terrain; +import com.jme3.terrain.geomipmap.MultiTerrainLodControl; +import com.jme3.terrain.geomipmap.NeighbourFinder; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import java.util.List; + +/** + * Demonstrates the NeighbourFinder interface for TerrainQuads, + * allowing you to tile terrains together without having to use + * TerrainGrid. It also introduces the MultiTerrainLodControl that + * will seam the edges of all the terrains supplied. + * + * @author sploreg + */ +public class TerrainTestTile extends SimpleApplication { + + private TiledTerrain terrain; + Material matTerrain; + Material matWire; + boolean wireframe = true; + boolean triPlanar = false; + boolean wardiso = false; + boolean minnaert = false; + protected BitmapText hintText; + private float grassScale = 256; + + + public static void main(String[] args) { + TerrainTestTile app = new TerrainTestTile(); + app.start(); + } + + + + @Override + public void simpleInitApp() { + loadHintText(); + setupKeys(); + + // WIREFRAME material + matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matWire.getAdditionalRenderState().setWireframe(true); + matWire.setColor("Color", ColorRGBA.Green); + + terrain = new TiledTerrain(); + rootNode.attachChild(terrain); + + DirectionalLight light = new DirectionalLight(); + light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); + rootNode.addLight(light); + + AmbientLight ambLight = new AmbientLight(); + ambLight.setColor(new ColorRGBA(1f, 1f, 0.8f, 0.2f)); + rootNode.addLight(ambLight); + + cam.setLocation(new Vector3f(0, 256, 0)); + cam.lookAtDirection(new Vector3f(0, -1, -1).normalizeLocal(), Vector3f.UNIT_Y); + + + Sphere s = new Sphere(12, 12, 3); + Geometry g = new Geometry("marker"); + g.setMesh(s); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.Red); + g.setMaterial(mat); + g.setLocalTranslation(0, -100, 0); + rootNode.attachChild(g); + + Geometry g2 = new Geometry("marker"); + g2.setMesh(s); + mat.setColor("Color", ColorRGBA.Red); + g2.setMaterial(mat); + g2.setLocalTranslation(10, -100, 0); + rootNode.attachChild(g2); + + Geometry g3 = new Geometry("marker"); + g3.setMesh(s); + mat.setColor("Color", ColorRGBA.Red); + g3.setMaterial(mat); + g3.setLocalTranslation(0, -100, 10); + rootNode.attachChild(g3); + } + + public void loadHintText() { + hintText = new BitmapText(guiFont, false); + hintText.setLocalTranslation(0, getCamera().getHeight(), 0); + hintText.setText("Hit 'T' to toggle wireframe"); + guiNode.attachChild(hintText); + } + + + private void setupKeys() { + flyCam.setMoveSpeed(100); + inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addListener(actionListener, "wireframe"); + } + private ActionListener actionListener = new ActionListener() { + + public void onAction(String name, boolean pressed, float tpf) { + if (name.equals("wireframe") && !pressed) { + wireframe = !wireframe; + if (!wireframe) { + terrain.setMaterial(matWire); + } else { + terrain.setMaterial(matTerrain); + } + } + } + }; + + /** + * A sample class (node in this case) that demonstrates + * the use of NeighbourFinder. + * It just links up the left,right,top,bottom TerrainQuads + * so LOD can work. + * It does not implement many of the Terrain interface's methods, + * you will want to do that for your own implementations. + */ + private class TiledTerrain extends Node implements Terrain, NeighbourFinder { + + private TerrainQuad terrain1; + private TerrainQuad terrain2; + private TerrainQuad terrain3; + private TerrainQuad terrain4; + + TiledTerrain() { + // TERRAIN TEXTURE material + matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matTerrain.setBoolean("useTriPlanarMapping", false); + matTerrain.setBoolean("WardIso", true); + matTerrain.setFloat("Shininess", 0); + + // GRASS texture + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matTerrain.setTexture("DiffuseMap", grass); + matTerrain.setFloat("DiffuseMap_0_scale", grassScale); + + // CREATE THE TERRAIN + terrain1 = new TerrainQuad("terrain 1", 65, 513, null); + terrain1.setMaterial(matTerrain); + terrain1.setLocalTranslation(-256, -100, -256); + terrain1.setLocalScale(1f, 1f, 1f); + this.attachChild(terrain1); + + terrain2 = new TerrainQuad("terrain 2", 65, 513, null); + terrain2.setMaterial(matTerrain); + terrain2.setLocalTranslation(-256, -100, 256); + terrain2.setLocalScale(1f, 1f, 1f); + this.attachChild(terrain2); + + terrain3 = new TerrainQuad("terrain 3", 65, 513, null); + terrain3.setMaterial(matTerrain); + terrain3.setLocalTranslation(256, -100, -256); + terrain3.setLocalScale(1f, 1f, 1f); + this.attachChild(terrain3); + + terrain4 = new TerrainQuad("terrain 4", 65, 513, null); + terrain4.setMaterial(matTerrain); + terrain4.setLocalTranslation(256, -100, 256); + terrain4.setLocalScale(1f, 1f, 1f); + this.attachChild(terrain4); + + terrain1.setNeighbourFinder(this); + terrain2.setNeighbourFinder(this); + terrain3.setNeighbourFinder(this); + terrain4.setNeighbourFinder(this); + + MultiTerrainLodControl lodControl = new MultiTerrainLodControl(getCamera()); + lodControl.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier + lodControl.addTerrain(terrain1); + lodControl.addTerrain(terrain2); + lodControl.addTerrain(terrain3);// order of these seems to matter + lodControl.addTerrain(terrain4); + this.addControl(lodControl); + + } + + /** + * 1 3 + * 2 4 + */ + public TerrainQuad getRightQuad(TerrainQuad center) { + //System.out.println("lookup neighbour"); + if (center == terrain1) + return terrain3; + if (center == terrain2) + return terrain4; + + return null; + } + + /** + * 1 3 + * 2 4 + */ + public TerrainQuad getLeftQuad(TerrainQuad center) { + //System.out.println("lookup neighbour"); + if (center == terrain3) + return terrain1; + if (center == terrain4) + return terrain2; + + return null; + } + + /** + * 1 3 + * 2 4 + */ + public TerrainQuad getTopQuad(TerrainQuad center) { + //System.out.println("lookup neighbour"); + if (center == terrain2) + return terrain1; + if (center == terrain4) + return terrain3; + + return null; + } + + /** + * 1 3 + * 2 4 + */ + public TerrainQuad getDownQuad(TerrainQuad center) { + //System.out.println("lookup neighbour"); + if (center == terrain1) + return terrain2; + if (center == terrain3) + return terrain4; + + return null; + } + + public float getHeight(Vector2f xz) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public Vector3f getNormal(Vector2f xz) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public float getHeightmapHeight(Vector2f xz) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setHeight(Vector2f xzCoordinate, float height) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setHeight(List xz, List height) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public void adjustHeight(Vector2f xzCoordinate, float delta) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public void adjustHeight(List xz, List height) { + // you will have to offset the coordinate for each terrain, to center on it + throw new UnsupportedOperationException("Not supported yet."); + } + + public float[] getHeightMap() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int getMaxLod() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setLocked(boolean locked) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void generateEntropy(ProgressMonitor monitor) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Material getMaterial() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Material getMaterial(Vector3f worldLocation) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int getTerrainSize() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int getNumMajorSubdivisions() { + throw new UnsupportedOperationException("Not supported yet."); + } + + + + } +} diff --git a/JmeTests/src/jme3test/texture/TestAnisotropicFilter.java b/JmeTests/src/jme3test/texture/TestAnisotropicFilter.java new file mode 100644 index 0000000..c8633f5 --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestAnisotropicFilter.java @@ -0,0 +1,116 @@ +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.ScreenshotAppState; +import com.jme3.asset.AssetManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Limits; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; +import com.jme3.texture.image.ImageRaster; +import com.jme3.util.BufferUtils; + +public class TestAnisotropicFilter extends SimpleApplication implements ActionListener { + + private int globalAniso = 1; + private int maxAniso = 1; + + @Override + public void simpleInitApp() { + maxAniso = renderer.getLimits().get(Limits.TextureAnisotropy); + + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(100); + cam.setLocation(new Vector3f(197.02617f, 4.6769195f, -194.89545f)); + cam.setRotation(new Quaternion(0.07921988f, 0.8992258f, -0.18292196f, 0.38943136f)); + Quad q = new Quad(1000, 1000); + q.scaleTextureCoordinates(new Vector2f(1000, 1000)); + Geometry geom = new Geometry("quad", q); + geom.rotate(-FastMath.HALF_PI, 0, 0); + geom.setMaterial(createCheckerBoardMaterial(assetManager)); + rootNode.attachChild(geom); + + inputManager.addMapping("higher", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("lower", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addListener(this, "higher"); + inputManager.addListener(this, "lower"); + } + + private static Material createCheckerBoardMaterial(AssetManager assetManager) { + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + Texture tex = createCheckerBoardTexture(); // assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds"); + tex.setMagFilter(Texture.MagFilter.Bilinear); + tex.setMinFilter(Texture.MinFilter.Trilinear); + tex.setWrap(Texture.WrapMode.Repeat); + mat.setTexture("ColorMap", tex); + return mat; + } + + private static Texture2D createCheckerBoardTexture() { + Image image = new Image(Format.RGBA8, 1024, 1024, BufferUtils.createByteBuffer(1024 * 1024 * 4), ColorSpace.sRGB); + + ImageRaster raster = ImageRaster.create(image); + for (int y = 0; y < 1024; y++) { + for (int x = 0; x < 1024; x++) { + if (y < 512) { + if (x < 512) { + raster.setPixel(x, y, ColorRGBA.Black); + } else { + raster.setPixel(x, y, ColorRGBA.White); + } + } else { + if (x < 512) { + raster.setPixel(x, y, ColorRGBA.White); + } else { + raster.setPixel(x, y, ColorRGBA.Black); + } + } + } + } + + return new Texture2D(image); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + return; + } + switch (name) { + case "higher": + globalAniso++; + if (globalAniso > 32) { + globalAniso = 32; + } + renderer.setDefaultAnisotropicFilter(globalAniso); + System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso); + break; + case "lower": + globalAniso--; + if (globalAniso < 1) { + globalAniso = 1; + } + renderer.setDefaultAnisotropicFilter(globalAniso); + System.out.format("Global Aniso: %d / %d\r\n", globalAniso, maxAniso); + break; + } + } + + public static void main(String[] args) { + TestAnisotropicFilter app = new TestAnisotropicFilter(); + app.start(); + } +} diff --git a/JmeTests/src/jme3test/texture/TestImageRaster.java b/JmeTests/src/jme3test/texture/TestImageRaster.java new file mode 100644 index 0000000..7084084 --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestImageRaster.java @@ -0,0 +1,162 @@ +package jme3test.texture; + + +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.font.Rectangle; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.MagFilter; +import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; +import com.jme3.texture.image.ImageRaster; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; + +public class TestImageRaster extends SimpleApplication { + + private Image convertImage(Image image, Format newFormat) { + int width = image.getWidth(); + int height = image.getHeight(); + ByteBuffer data = BufferUtils.createByteBuffer( (int)Math.ceil(newFormat.getBitsPerPixel() / 8.0) * width * height); + Image convertedImage = new Image(newFormat, width, height, data,null, image.getColorSpace()); + + ImageRaster sourceReader = ImageRaster.create(image); + ImageRaster targetWriter = ImageRaster.create(convertedImage); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + ColorRGBA color = sourceReader.getPixel(x, y); + targetWriter.setPixel(x, y, color); + } + } + + return convertedImage; + } + + private void convertAndPutImage(Image image, float posX, float posY) { + Texture tex = new Texture2D(image); + tex.setMagFilter(MagFilter.Nearest); + tex.setMinFilter(MinFilter.NearestNoMipMaps); + tex.setAnisotropicFilter(16); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", tex); + + Quad q = new Quad(5, 5); + Geometry g = new Geometry("quad", q); + g.setLocalTranslation(posX, posY - 5, -0.0001f); + g.setMaterial(mat); + rootNode.attachChild(g); + + BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); + BitmapText txt = new BitmapText(fnt); + txt.setBox(new Rectangle(0, 0, 5, 5)); + txt.setQueueBucket(RenderQueue.Bucket.Transparent); + txt.setSize(0.5f); + txt.setText(image.getFormat().name()); + txt.setLocalTranslation(posX, posY, 0); + rootNode.attachChild(txt); + } + + private Image createTestImage() { + Image testImage = new Image(Format.BGR8, 4, 3, BufferUtils.createByteBuffer(4 * 4 * 3), null, ColorSpace.Linear); + + ImageRaster io = ImageRaster.create(testImage); + io.setPixel(0, 0, ColorRGBA.Black); + io.setPixel(1, 0, ColorRGBA.Gray); + io.setPixel(2, 0, ColorRGBA.White); + io.setPixel(3, 0, ColorRGBA.White.mult(4)); // HDR color + + io.setPixel(0, 1, ColorRGBA.Red); + io.setPixel(1, 1, ColorRGBA.Green); + io.setPixel(2, 1, ColorRGBA.Blue); + io.setPixel(3, 1, new ColorRGBA(0, 0, 0, 0)); + + io.setPixel(0, 2, ColorRGBA.Yellow); + io.setPixel(1, 2, ColorRGBA.Magenta); + io.setPixel(2, 2, ColorRGBA.Cyan); + io.setPixel(3, 2, new ColorRGBA(1, 1, 1, 0)); + + return testImage; + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(16, 6, 36)); + flyCam.setMoveSpeed(10); + + Texture tex = assetManager.loadTexture("com/jme3/app/Monkey.png"); +// Texture tex = assetManager.loadTexture("Textures/HdrTest/Memorial.hdr"); + Image originalImage = tex.getImage(); + + Image image = convertImage(originalImage, Format.RGBA32F); + convertAndPutImage(image, 0, 0); + + image = convertImage(image, Format.RGB32F); + convertAndPutImage(image, 5, 0); + + image = convertImage(image, Format.RGBA16F); + convertAndPutImage(image, 10, 0); + + image = convertImage(image, Format.RGB16F); + convertAndPutImage(image, 15, 0); + + image = convertImage(image, Format.RGB16F_to_RGB9E5); + convertAndPutImage(image, 20, 0); + + image = convertImage(image, Format.RGB16F_to_RGB111110F); + convertAndPutImage(image, 25, 0); + + image = convertImage(image, Format.RGBA8); + convertAndPutImage(image, 10, 5); + + image = convertImage(image, Format.RGB8); + convertAndPutImage(image, 15, 5); + + image = convertImage(image, Format.ABGR8); + convertAndPutImage(image, 20, 5); + + image = convertImage(image, Format.BGR8); + convertAndPutImage(image, 25, 5); + + image = convertImage(image, Format.ARGB8); + convertAndPutImage(image, 30, 5); + + image = convertImage(image, Format.BGRA8); + convertAndPutImage(image, 35, 5); + + image = convertImage(image, Format.RGB5A1); + convertAndPutImage(image, 0, 10); + + image = convertImage(image, Format.RGB565); + convertAndPutImage(image, 5, 10); + + image = convertImage(image, Format.Luminance32F); + convertAndPutImage(image, 0, 15); + + image = convertImage(image, Format.Luminance16FAlpha16F); + convertAndPutImage(image, 5, 15); + + image = convertImage(image, Format.Luminance16F); + convertAndPutImage(image, 10, 15); + + image = convertImage(image, Format.Luminance8Alpha8); + convertAndPutImage(image, 15, 15); + + image = convertImage(image, Format.Luminance8); + convertAndPutImage(image, 20, 15); + } + + public static void main(String[] args) { + TestImageRaster app = new TestImageRaster(); + app.start(); + } +} diff --git a/JmeTests/src/jme3test/texture/TestSkyLoading.java b/JmeTests/src/jme3test/texture/TestSkyLoading.java new file mode 100644 index 0000000..7991bd0 --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestSkyLoading.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.scene.Spatial; +import com.jme3.texture.Texture; +import com.jme3.util.SkyFactory; + +public class TestSkyLoading extends SimpleApplication { + + public static void main(String[] args){ + TestSkyLoading app = new TestSkyLoading(); + app.start(); + } + + public void simpleInitApp() { + Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); + Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); + Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); + Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); + Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); + Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); + + Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); + rootNode.attachChild(sky); + } + +} diff --git a/JmeTests/src/jme3test/texture/TestSkyRotation.java b/JmeTests/src/jme3test/texture/TestSkyRotation.java new file mode 100644 index 0000000..f57e71f --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestSkyRotation.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2017 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; + +/** + * Simple application to test sky rotation with a cube-mapped sky. + * + * Press "T" to rotate the sky and floor to the camera's left. Press "Y" to + * rotate the sky and floor to the camera's right. Both should appear to move by + * the same amount in the same direction. + * + * See issue #651 for further information. + * + * @author Stephen Gold + */ +public class TestSkyRotation extends SimpleApplication implements ActionListener { + + /** + * objects visible in the scene + */ + private Spatial floor, sky; + /** + * Y-axis rotation angle in radians + */ + private float angle = 0f; + + public static void main(String[] arguments) { + TestSkyRotation application = new TestSkyRotation(); + application.start(); + } + + @Override + public void simpleInitApp() { + /* + * Configure the camera. + */ + flyCam.setEnabled(false); + Vector3f location = new Vector3f(-7f, 4f, 8f); + cam.setLocation(location); + Quaternion orientation; + orientation = new Quaternion(0.0037f, 0.944684f, -0.01067f, 0.327789f); + assert FastMath.approximateEquals(orientation.norm(), 1f); + cam.setRotation(orientation); + /* + * Attach a cube-mapped sky to the scene graph. + */ + sky = SkyFactory.createSky(assetManager, + "Scenes/Beach/FullskiesSunset0068.dds", + SkyFactory.EnvMapType.CubeMap); + rootNode.attachChild(sky); + /* + * Attach a "floor" geometry to the scene graph. + */ + Mesh floorMesh = new Box(10f, 0.1f, 10f); + floor = new Geometry("floor", floorMesh); + Material floorMaterial = new Material(assetManager, + "Common/MatDefs/Misc/Unshaded.j3md"); + floorMaterial.setTexture("ColorMap", + assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + floor.setMaterial(floorMaterial); + rootNode.attachChild(floor); + /* + * Configure mappings and listeners for keyboard input. + */ + inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addListener(this, "left"); + inputManager.addListener(this, "right"); + } + + /** + * Handle an input action from the user. + * + * @param name the name of the action + * @param ongoing true→depress key, false→release key + * @param ignored + */ + @Override + public void onAction(String name, boolean ongoing, float ignored) { + if (!ongoing) { + return; + } + /* + * Update the Y-axis rotation angle based on which key was pressed. + */ + if (name.equals("left")) { + angle += 0.1f; // radians + System.out.print("rotate floor and sky leftward ..."); + } else if (name.equals("right")) { + angle -= 0.1f; // radians + System.out.printf("rotate floor and sky spatials rightward ..."); + } else { + return; + } + /* + * Update the local rotations of both objects based on the angle. + */ + System.out.printf(" to %.1f radians left of start%n", angle); + Quaternion rotation = new Quaternion(); + rotation.fromAngleNormalAxis(angle, Vector3f.UNIT_Y); + floor.setLocalRotation(rotation); + sky.setLocalRotation(rotation); + } +} diff --git a/JmeTests/src/jme3test/texture/TestTexture3D.java b/JmeTests/src/jme3test/texture/TestTexture3D.java new file mode 100644 index 0000000..a7e553a --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestTexture3D.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.bounding.BoundingBox; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.VertexBuffer; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.VertexBuffer.Usage; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture3D; +import com.jme3.texture.image.ColorSpace; +import com.jme3.util.BufferUtils; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.ArrayList; + +public class TestTexture3D extends SimpleApplication { + + public static void main(String[] args) { + TestTexture3D app = new TestTexture3D(); + app.start(); + } + + @Override + public void simpleInitApp() { + //mouseInput.setCursorVisible(true); + flyCam.setMoveSpeed(10); + //creating a sphere + Sphere sphere = new Sphere(32, 32, 1); + //getting the boundingbox + sphere.updateBound(); + BoundingBox bb = (BoundingBox) sphere.getBound(); + Vector3f min = bb.getMin(null); + float[] ext = new float[]{bb.getXExtent() * 2, bb.getYExtent() * 2, bb.getZExtent() * 2}; + //we need to change the UV coordinates (the sphere is assumet to be inside the 3D image box) + sphere.clearBuffer(Type.TexCoord); + VertexBuffer vb = sphere.getBuffer(Type.Position); + FloatBuffer fb = (FloatBuffer) vb.getData(); + float[] uvCoordinates = BufferUtils.getFloatArray(fb); + //now transform the coordinates so that they are in the range of <0; 1> + for (int i = 0; i < uvCoordinates.length; i += 3) { + uvCoordinates[i] = (uvCoordinates[i] - min.x) / ext[0]; + uvCoordinates[i + 1] = (uvCoordinates[i + 1] - min.y) / ext[1]; + uvCoordinates[i + 2] = (uvCoordinates[i + 2] - min.z) / ext[2]; + } + //apply new texture coordinates + VertexBuffer uvCoordsBuffer = new VertexBuffer(Type.TexCoord); + uvCoordsBuffer.setupData(Usage.Static, 3, com.jme3.scene.VertexBuffer.Format.Float, + BufferUtils.createFloatBuffer(uvCoordinates)); + sphere.setBuffer(uvCoordsBuffer); + //create geometry, and apply material and our 3D texture + Geometry g = new Geometry("sphere", sphere); + Material material = new Material(assetManager, "jme3test/texture/tex3D.j3md"); + try { + Texture texture = this.getTexture(); + material.setTexture("Texture", texture); + } catch (IOException e) { + e.printStackTrace(); + } + g.setMaterial(material); + rootNode.attachChild(g); + //add some light so that it is visible + PointLight light = new PointLight(); + light.setColor(ColorRGBA.White); + light.setPosition(new Vector3f(5, 5, 5)); + light.setRadius(20); + rootNode.addLight(light); + light = new PointLight(); + light.setColor(ColorRGBA.White); + light.setPosition(new Vector3f(-5, -5, -5)); + light.setRadius(20); + rootNode.addLight(light); + } + + /** + * This method creates a RGB8 texture with the sizes of 10x10x10 pixels. + */ + private Texture getTexture() throws IOException { + ArrayList data = new ArrayList(1); + ByteBuffer bb = BufferUtils.createByteBuffer(10 * 10 * 10 * 3);//all data must be inside one buffer + for (int i = 0; i < 10; ++i) { + for (int j = 0; j < 10 * 10; ++j) { + bb.put((byte) (255f*i/10f)); + bb.put((byte) (255f*i/10f)); + bb.put((byte) (255f)); + } + } + bb.rewind(); + data.add(bb); + return new Texture3D(new Image(Format.RGB8, 10, 10, 10, data, null, ColorSpace.Linear)); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/TestTexture3DLoading.java b/JmeTests/src/jme3test/texture/TestTexture3DLoading.java new file mode 100644 index 0000000..4e33cbc --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestTexture3DLoading.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.texture; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.texture.Texture; + +public class TestTexture3DLoading extends SimpleApplication { + + public static void main(String[] args) { + TestTexture3DLoading app = new TestTexture3DLoading(); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + flyCam.setEnabled(false); + + + Quad q = new Quad(10, 10); + + Geometry geom = new Geometry("Quad", q); + Material material = new Material(assetManager, "jme3test/texture/tex3DThumb.j3md"); + TextureKey key = new TextureKey("Textures/3D/flame.dds"); + key.setGenerateMips(true); + key.setTextureTypeHint(Texture.Type.ThreeDimensional); + + Texture t = assetManager.loadTexture(key); + + int rows = 4;//4 * 4 + + q.scaleTextureCoordinates(new Vector2f(rows, rows)); + + //The image only have 8 pictures and we have 16 thumbs, the data will be interpolated by the GPU + material.setFloat("InvDepth", 1f / 16f); + material.setInt("Rows", rows); + material.setTexture("Texture", t); + geom.setMaterial(material); + + rootNode.attachChild(geom); + + cam.setLocation(new Vector3f(4.7444625f, 5.160054f, 13.1939f)); + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/TestTextureArray.java b/JmeTests/src/jme3test/texture/TestTextureArray.java new file mode 100644 index 0000000..391e4ef --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestTextureArray.java @@ -0,0 +1,87 @@ +package jme3test.texture; + + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Caps; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.TextureArray; +import com.jme3.util.BufferUtils; +import java.util.ArrayList; +import java.util.List; + +public class TestTextureArray extends SimpleApplication +{ + + @Override + public void simpleInitApp() + { + Material mat = new Material(assetManager, "jme3test/texture/UnshadedArray.j3md"); + + for (Caps caps : renderManager.getRenderer().getCaps()) { + System.out.println(caps.name()); + } + if(!renderManager.getRenderer().getCaps().contains(Caps.TextureArray)){ + throw new UnsupportedOperationException("Your hardware does not support TextureArray"); + } + + + Texture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond.jpg"); + Texture tex2 = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + List images = new ArrayList(); + images.add(tex1.getImage()); + images.add(tex2.getImage()); + TextureArray tex3 = new TextureArray(images); + tex3.setMinFilter(Texture.MinFilter.Trilinear); + mat.setTexture("ColorMap", tex3); + + Mesh m = new Mesh(); + Vector3f[] vertices = new Vector3f[8]; + vertices[0] = new Vector3f(0, 0, 0); + vertices[1] = new Vector3f(3, 0, 0); + vertices[2] = new Vector3f(0, 3, 0); + vertices[3] = new Vector3f(3, 3, 0); + + vertices[4] = new Vector3f(3, 0, 0); + vertices[5] = new Vector3f(6, 0, 0); + vertices[6] = new Vector3f(3, 3, 0); + vertices[7] = new Vector3f(6, 3, 0); + + Vector3f[] texCoord = new Vector3f[8]; + texCoord[0] = new Vector3f(0, 0, 0); + texCoord[1] = new Vector3f(1, 0, 0); + texCoord[2] = new Vector3f(0, 1, 0); + texCoord[3] = new Vector3f(1, 1, 0); + + texCoord[4] = new Vector3f(0, 0, 1); + texCoord[5] = new Vector3f(1, 0, 1); + texCoord[6] = new Vector3f(0, 1, 1); + texCoord[7] = new Vector3f(1, 1, 1); + + int[] indexes = { 2, 0, 1, 1, 3, 2 , 6, 4, 5, 5, 7, 6}; + + m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices)); + m.setBuffer(Type.TexCoord, 3, BufferUtils.createFloatBuffer(texCoord)); + m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes)); + m.updateBound(); + + Geometry geom = new Geometry("Mesh", m); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + /** + * @param args + */ + public static void main(String[] args) + { + TestTextureArray app = new TestTextureArray(); + app.start(); + } + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/TestTextureArrayCompressed.java b/JmeTests/src/jme3test/texture/TestTextureArrayCompressed.java new file mode 100644 index 0000000..2187c58 --- /dev/null +++ b/JmeTests/src/jme3test/texture/TestTextureArrayCompressed.java @@ -0,0 +1,87 @@ +package jme3test.texture; + + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Caps; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.TextureArray; +import com.jme3.util.BufferUtils; +import java.util.ArrayList; +import java.util.List; + +public class TestTextureArrayCompressed extends SimpleApplication +{ + + @Override + public void simpleInitApp() + { + Material mat = new Material(assetManager, "jme3test/texture/UnshadedArray.j3md"); + + for (Caps caps : renderManager.getRenderer().getCaps()) { + System.out.println(caps.name()); + } + if(!renderManager.getRenderer().getCaps().contains(Caps.TextureArray)){ + throw new UnsupportedOperationException("Your hardware does not support TextureArray"); + } + + + Texture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond.dds"); + Texture tex2 = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds"); + List images = new ArrayList(); + images.add(tex1.getImage()); + images.add(tex2.getImage()); + TextureArray tex3 = new TextureArray(images); + tex3.setMinFilter(Texture.MinFilter.Trilinear); + mat.setTexture("ColorMap", tex3); + + Mesh m = new Mesh(); + Vector3f[] vertices = new Vector3f[8]; + vertices[0] = new Vector3f(0, 0, 0); + vertices[1] = new Vector3f(3, 0, 0); + vertices[2] = new Vector3f(0, 3, 0); + vertices[3] = new Vector3f(3, 3, 0); + + vertices[4] = new Vector3f(3, 0, 0); + vertices[5] = new Vector3f(6, 0, 0); + vertices[6] = new Vector3f(3, 3, 0); + vertices[7] = new Vector3f(6, 3, 0); + + Vector3f[] texCoord = new Vector3f[8]; + texCoord[0] = new Vector3f(0, 0, 0); + texCoord[1] = new Vector3f(1, 0, 0); + texCoord[2] = new Vector3f(0, 1, 0); + texCoord[3] = new Vector3f(1, 1, 0); + + texCoord[4] = new Vector3f(0, 0, 1); + texCoord[5] = new Vector3f(1, 0, 1); + texCoord[6] = new Vector3f(0, 1, 1); + texCoord[7] = new Vector3f(1, 1, 1); + + int[] indexes = { 2, 0, 1, 1, 3, 2 , 6, 4, 5, 5, 7, 6}; + + m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices)); + m.setBuffer(Type.TexCoord, 3, BufferUtils.createFloatBuffer(texCoord)); + m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes)); + m.updateBound(); + + Geometry geom = new Geometry("Mesh", m); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + /** + * @param args + */ + public static void main(String[] args) + { + TestTextureArrayCompressed app = new TestTextureArrayCompressed(); + app.start(); + } + +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/UnshadedArray.frag b/JmeTests/src/jme3test/texture/UnshadedArray.frag new file mode 100644 index 0000000..4839acf --- /dev/null +++ b/JmeTests/src/jme3test/texture/UnshadedArray.frag @@ -0,0 +1,57 @@ +#extension GL_EXT_texture_array : enable +// #extension GL_EXT_gpu_shader4 : enable + +uniform vec4 m_Color; + +#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#ifdef HAS_COLORMAP + #if !defined(GL_EXT_texture_array) + #error Texture arrays are not supported, but required for this shader. + #endif + + uniform sampler2DArray m_ColorMap; +#endif + +#ifdef NEED_TEXCOORD1 + varying vec3 texCoord1; +#endif + +#ifdef HAS_LIGHTMAP + uniform sampler2D m_LightMap; + #ifdef SEPERATE_TEXCOORD + varying vec3 texCoord2; + #endif +#endif + +#ifdef HAS_VERTEXCOLOR + varying vec4 vertColor; +#endif + +void main(){ + vec4 color = vec4(1.0); + + #ifdef HAS_COLORMAP + color *= texture2DArray(m_ColorMap, texCoord1); + #endif + + #ifdef HAS_VERTEXCOLOR + color *= vertColor; + #endif + + #ifdef HAS_COLOR + color *= m_Color; + #endif + + #ifdef HAS_LIGHTMAP + #ifdef SEPARATE_TEXCOORD + color.rgb *= texture2D(m_LightMap, texCoord2).rgb; + #else + color.rgb *= texture2D(m_LightMap, texCoord1).rgb; + #endif + #endif + + gl_FragColor = color; +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/UnshadedArray.j3md b/JmeTests/src/jme3test/texture/UnshadedArray.j3md new file mode 100644 index 0000000..dafa36c --- /dev/null +++ b/JmeTests/src/jme3test/texture/UnshadedArray.j3md @@ -0,0 +1,66 @@ +MaterialDef Unshaded { + + MaterialParameters { + TextureArray ColorMap + Texture2D LightMap + Color Color (Color) + Boolean VertexColor + Boolean SeparateTexCoord + + // Texture of the glowing parts of the material + Texture2D GlowMap + // The glow color of the object + Color GlowColor + } + + Technique { + VertexShader GLSL100: jme3test/texture/UnshadedArray.vert + FragmentShader GLSL100: jme3test/texture/UnshadedArray.frag + + WorldParameters { + WorldViewProjectionMatrix + } + + Defines { + SEPARATE_TEXCOORD : SeparateTexCoord + HAS_COLORMAP : ColorMap + HAS_LIGHTMAP : LightMap + HAS_VERTEXCOLOR : VertexColor + HAS_COLOR : Color + } + } + + Technique PreNormalPass { + + VertexShader GLSL100 : Common/MatDefs/SSAO/normal.vert + FragmentShader GLSL100 : Common/MatDefs/SSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + } + + RenderState { + + } + + } + + + Technique Glow { + + VertexShader GLSL100: Cjme3test/texture/UnshadedArray.vert + FragmentShader GLSL100: Common/MatDefs/Light/Glow.frag + + WorldParameters { + WorldViewProjectionMatrix + } + + Defines { + HAS_GLOWMAP : GlowMap + HAS_GLOWCOLOR : GlowColor + HAS_COLORMAP // Must be passed so that Unshaded.vert exports texCoord. + } + } +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/UnshadedArray.vert b/JmeTests/src/jme3test/texture/UnshadedArray.vert new file mode 100644 index 0000000..b4eb2d1 --- /dev/null +++ b/JmeTests/src/jme3test/texture/UnshadedArray.vert @@ -0,0 +1,38 @@ +uniform mat4 g_WorldViewProjectionMatrix; +attribute vec3 inPosition; + +#if defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#ifdef NEED_TEXCOORD1 + attribute vec3 inTexCoord; + varying vec3 texCoord1; +#endif + +#ifdef SEPARATE_TEXCOORD + attribute vec3 inTexCoord2; + varying vec3 texCoord2; +#endif + +#ifdef HAS_VERTEXCOLOR + attribute vec4 inColor; + varying vec4 vertColor; +#endif + +void main(){ + #ifdef NEED_TEXCOORD1 + texCoord1 = inTexCoord; + #endif + + #ifdef SEPARATE_TEXCOORD + texCoord2 = inTexCoord2; + #endif + + #ifdef HAS_VERTEXCOLOR + vertColor = inColor; + #endif + + gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); +} + diff --git a/JmeTests/src/jme3test/texture/ktx/TestLoadKtx.java b/JmeTests/src/jme3test/texture/ktx/TestLoadKtx.java new file mode 100644 index 0000000..62330be --- /dev/null +++ b/JmeTests/src/jme3test/texture/ktx/TestLoadKtx.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.texture.ktx; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Node; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.texture.TextureCubeMap; +import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.ui.Picture; + +/** + * test + * @author nehon + */ +public class TestLoadKtx extends SimpleApplication { + + public static void main(String[] args) { + TestLoadKtx app = new TestLoadKtx(); + //app.setShowSettings(false); + app.start(); + } + + @Override + public void simpleInitApp() { + viewPort.setBackgroundColor(ColorRGBA.DarkGray); + assetManager.registerLoader(KTXLoader.class, "ktx"); + + + Texture2D t = (Texture2D)assetManager.loadTexture("Textures/ktx/down-reference.ktx"); + Picture p = new Picture("bla", false); + p.setTexture(assetManager, t, false); + p.setLocalTranslation(200, 200, 0); + p.setWidth(t.getImage().getWidth()); + p.setHeight(t.getImage().getHeight()); + guiNode.attachChild(p); + + + Texture2D t2 = (Texture2D)assetManager.loadTexture("Textures/ktx/up-reference.ktx"); + Picture p2 = new Picture("bla", false); + p2.setTexture(assetManager, t2, false); + p2.setLocalTranslation(400, 200, 0); + p2.setWidth(t2.getImage().getWidth()); + p2.setHeight(t2.getImage().getHeight()); + guiNode.attachChild(p2); + + Texture2D t3 = (Texture2D)assetManager.loadTexture("Textures/ktx/rgba-reference.ktx"); + Picture p3 = new Picture("bla", false); + p3.setTexture(assetManager, t3, false); + p3.setLocalTranslation(200, 400, 0); + p3.setWidth(t3.getImage().getWidth()); + p3.setHeight(t3.getImage().getHeight()); + guiNode.attachChild(p3); + + + Texture2D t4 = (Texture2D)assetManager.loadTexture("Textures/ktx/rgb-amg-reference.ktx"); + Picture p4 = new Picture("bla", false); + p4.setTexture(assetManager, t4, false); + p4.setLocalTranslation(400, 400, 0); + p4.setWidth(t4.getImage().getWidth()); + p4.setHeight(t4.getImage().getHeight()); + guiNode.attachChild(p4); + + + flyCam.setDragToRotate(true); + + } + + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } +} diff --git a/JmeTests/src/jme3test/texture/tex3D.frag b/JmeTests/src/jme3test/texture/tex3D.frag new file mode 100644 index 0000000..2f969dc --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3D.frag @@ -0,0 +1,7 @@ +uniform sampler3D m_Texture; + +varying vec3 texCoord; + +void main(){ + gl_FragColor= texture3D(m_Texture,texCoord); +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/tex3D.j3md b/JmeTests/src/jme3test/texture/tex3D.j3md new file mode 100644 index 0000000..1ba2605 --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3D.j3md @@ -0,0 +1,16 @@ +MaterialDef My MaterialDef { + + MaterialParameters { + Texture3D Texture + } + + Technique { + VertexShader GLSL100: jme3test/texture/tex3D.vert + FragmentShader GLSL100: jme3test/texture/tex3D.frag + + WorldParameters { + WorldViewProjectionMatrix + } + } + +} diff --git a/JmeTests/src/jme3test/texture/tex3D.vert b/JmeTests/src/jme3test/texture/tex3D.vert new file mode 100644 index 0000000..d5fb99b --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3D.vert @@ -0,0 +1,11 @@ +uniform mat4 g_WorldViewProjectionMatrix; + +attribute vec3 inTexCoord; +attribute vec3 inPosition; + +varying vec3 texCoord; + +void main(){ + gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition,1.0); + texCoord=inTexCoord; +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/tex3DThumb.frag b/JmeTests/src/jme3test/texture/tex3DThumb.frag new file mode 100644 index 0000000..8f4cdfc --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3DThumb.frag @@ -0,0 +1,15 @@ +uniform sampler3D m_Texture; +uniform int m_Rows; +uniform float m_InvDepth; + +varying vec2 texCoord; + +void main(){ + float rows = float(m_Rows); + float depthx = floor(texCoord.x); + float depthy = (rows - 1.0) - floor(texCoord.y); + //vec3 texC=vec3(texCoord.x,texCoord.y ,0.7);// + + vec3 texC = vec3(fract(texCoord.x),fract(texCoord.y),(depthy * rows + depthx) * m_InvDepth); + gl_FragColor = texture3D(m_Texture, texC); +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/texture/tex3DThumb.j3md b/JmeTests/src/jme3test/texture/tex3DThumb.j3md new file mode 100644 index 0000000..a42bd38 --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3DThumb.j3md @@ -0,0 +1,18 @@ +MaterialDef Tex3DThumb { + + MaterialParameters { + Texture3D Texture + Int Rows; + Float InvDepth; + } + + Technique { + VertexShader GLSL100: jme3test/texture/tex3DThumb.vert + FragmentShader GLSL100: jme3test/texture/tex3DThumb.frag + + WorldParameters { + WorldViewProjectionMatrix + } + } + +} diff --git a/JmeTests/src/jme3test/texture/tex3DThumb.vert b/JmeTests/src/jme3test/texture/tex3DThumb.vert new file mode 100644 index 0000000..b841463 --- /dev/null +++ b/JmeTests/src/jme3test/texture/tex3DThumb.vert @@ -0,0 +1,11 @@ +uniform mat4 g_WorldViewProjectionMatrix; + +attribute vec2 inTexCoord; +attribute vec3 inPosition; + +varying vec2 texCoord; + +void main(){ + gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition,1.0); + texCoord=inTexCoord; +} \ No newline at end of file diff --git a/JmeTests/src/jme3test/tools/TestSaveGame.java b/JmeTests/src/jme3test/tools/TestSaveGame.java new file mode 100644 index 0000000..8e90d18 --- /dev/null +++ b/JmeTests/src/jme3test/tools/TestSaveGame.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2018 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.tools; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import jme3tools.savegame.SaveGame; + +public class TestSaveGame extends SimpleApplication { + + public static void main(String[] args) { + + TestSaveGame app = new TestSaveGame(); + app.start(); + } + + @Override + public void simpleUpdate(float tpf) { + } + + public void simpleInitApp() { + + //node that is used to store player data + Node myPlayer = new Node(); + myPlayer.setName("PlayerNode"); + myPlayer.setUserData("name", "Mario"); + myPlayer.setUserData("health", 100.0f); + myPlayer.setUserData("points", 0); + + //the actual model would be attached to this node + Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + myPlayer.attachChild(model); + + //before saving the game, the model should be detached so it's not saved along with the node + myPlayer.detachAllChildren(); + SaveGame.saveGame("mycompany/mygame", "savegame_001", myPlayer); + + //later the game is loaded again + Node player = (Node) SaveGame.loadGame("mycompany/mygame", "savegame_001"); + player.attachChild(model); + rootNode.attachChild(player); + + //and the data is available + System.out.println("Name: " + player.getUserData("name")); + System.out.println("Health: " + player.getUserData("health")); + System.out.println("Points: " + player.getUserData("points")); + + AmbientLight al = new AmbientLight(); + rootNode.addLight(al); + + //note you can also implement your own classes that implement the Savable interface. + } +} diff --git a/JmeTests/src/jme3test/tools/TestTextureAtlas.java b/JmeTests/src/jme3test/tools/TestTextureAtlas.java new file mode 100644 index 0000000..5c3d6c9 --- /dev/null +++ b/JmeTests/src/jme3test/tools/TestTextureAtlas.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.tools; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import jme3tools.optimize.TextureAtlas; + +public class TestTextureAtlas extends SimpleApplication { + + public static void main(String[] args) { + TestTextureAtlas app = new TestTextureAtlas(); + app.start(); + } + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(50); + Node scene = new Node("Scene"); + Spatial obj1 = assetManager.loadModel("Models/Ferrari/Car.scene"); + obj1.setLocalTranslation(-4, 0, 0); + Spatial obj2 = assetManager.loadModel("Models/Oto/Oto.mesh.xml"); + obj2.setLocalTranslation(-2, 0, 0); + Spatial obj3 = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml"); + obj3.setLocalTranslation(-0, 0, 0); + Spatial obj4 = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml"); + obj4.setLocalTranslation(2, 0, 0); + Spatial obj5 = assetManager.loadModel("Models/Tree/Tree.mesh.j3o"); + obj5.setLocalTranslation(4, 0, 0); + scene.attachChild(obj1); + scene.attachChild(obj2); + scene.attachChild(obj3); + scene.attachChild(obj4); + scene.attachChild(obj5); + + Geometry geom = TextureAtlas.makeAtlasBatch(scene, assetManager, 2048); + + AmbientLight al = new AmbientLight(); + rootNode.addLight(al); + + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(new Vector3f(0.69077975f, -0.6277887f, -0.35875428f).normalizeLocal()); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + rootNode.addLight(sun); + + rootNode.attachChild(geom); + + //quad to display material + Geometry box = new Geometry("displayquad", new Quad(4, 4)); + box.setMaterial(geom.getMaterial()); + box.setLocalTranslation(0, 1, 3); + rootNode.attachChild(box); + } +} diff --git a/JmeTests/src/jme3test/water/TestMultiPostWater.java b/JmeTests/src/jme3test/water/TestMultiPostWater.java new file mode 100644 index 0000000..2611d96 --- /dev/null +++ b/JmeTests/src/jme3test/water/TestMultiPostWater.java @@ -0,0 +1,189 @@ +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.system.AppSettings; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.Texture2D; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import com.jme3.water.WaterFilter; +import java.util.ArrayList; +import java.util.List; + +/** + * test + * + * @author normenhansen + */ +public class TestMultiPostWater extends SimpleApplication { + + private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f); + private WaterFilter water; + private TerrainQuad terrain; + private Material matRock; + private static float WATER_HEIGHT = 90; + + public static void main(String[] args) { + TestMultiPostWater app = new TestMultiPostWater(); + AppSettings s = new AppSettings(true); + s.setRenderer(AppSettings.LWJGL_OPENGL2); + s.setAudioRenderer(AppSettings.LWJGL_OPENAL); +// +// s.setRenderer("JOGL"); +// s.setAudioRenderer("JOAL"); + app.setSettings(s); + + app.start(); + } + + @Override + public void simpleInitApp() { + +// setDisplayFps(false); +// setDisplayStatView(false); + + Node mainScene = new Node("Main Scene"); + rootNode.attachChild(mainScene); + + createTerrain(mainScene); + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(1.7f)); + mainScene.addLight(sun); + + flyCam.setMoveSpeed(100); + + //cam.setLocation(new Vector3f(-700, 100, 300)); + //cam.setRotation(new Quaternion().fromAngleAxis(0.5f, Vector3f.UNIT_Z)); + cam.setLocation(new Vector3f(-327.21957f, 251.6459f, 126.884346f)); + cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0})); + + + Spatial sky = SkyFactory.createSky(assetManager, + "Scenes/Beach/FullskiesSunset0068.dds", EnvMapType.CubeMap); + sky.setLocalScale(350); + + mainScene.attachChild(sky); + cam.setFrustumFar(4000); + + + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + water = new WaterFilter(rootNode, lightDir); + water.setCenter(new Vector3f(9.628218f, -15.830074f, 199.23595f)); + water.setRadius(260); + water.setWaveScale(0.003f); + water.setMaxAmplitude(2f); + water.setFoamExistence(new Vector3f(1f, 4, 0.5f)); + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + water.setRefractionStrength(0.2f); + water.setWaterHeight(WATER_HEIGHT); + fpp.addFilter(water); + + WaterFilter water2 = new WaterFilter(rootNode, lightDir); + water2.setCenter(new Vector3f(-280.46027f, -24.971727f, -271.71976f)); + water2.setRadius(260); + water2.setWaterHeight(WATER_HEIGHT); + water2.setUseFoam(false); + water2.setUseRipples(false); + water2.setDeepWaterColor(ColorRGBA.Brown); + water2.setWaterColor(ColorRGBA.Brown.mult(2.0f)); + water2.setWaterTransparency(0.2f); + water2.setMaxAmplitude(0.3f); + water2.setWaveScale(0.008f); + water2.setSpeed(0.7f); + water2.setShoreHardness(1.0f); + water2.setRefractionConstant(0.2f); + water2.setShininess(0.3f); + water2.setSunScale(1.0f); + water2.setColorExtinction(new Vector3f(10.0f, 20.0f, 30.0f)); + fpp.addFilter(water2); + + + WaterFilter water3 = new WaterFilter(rootNode, lightDir); + water3.setCenter(new Vector3f(319.6663f, -18.367947f, -236.67674f)); + water3.setRadius(260); + water3.setWaterHeight(WATER_HEIGHT); + water3.setWaveScale(0.003f); + water3.setMaxAmplitude(2f); + water3.setFoamExistence(new Vector3f(1f, 4, 0.5f)); + water3.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + water3.setRefractionStrength(0.2f); + water3.setDeepWaterColor(ColorRGBA.Red); + water3.setWaterColor(ColorRGBA.Red.mult(2.0f)); + water3.setLightColor(ColorRGBA.Red); + fpp.addFilter(water3); + + viewPort.addProcessor(fpp); + + //fpp.setNumSamples(4); + } + + private void createTerrain(Node rootNode) { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/pools.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(5, 5, 5)); + terrain.setLocalTranslation(new Vector3f(0, -30, 0)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(terrain); + + } + + @Override + public void simpleUpdate(float tpf) { + } +} diff --git a/JmeTests/src/jme3test/water/TestPostWater.java b/JmeTests/src/jme3test/water/TestPostWater.java new file mode 100644 index 0000000..21e11d1 --- /dev/null +++ b/JmeTests/src/jme3test/water/TestPostWater.java @@ -0,0 +1,327 @@ +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.audio.AudioData.DataType; +import com.jme3.audio.AudioNode; +import com.jme3.audio.LowPassFilter; +import com.jme3.effect.ParticleEmitter; +import com.jme3.effect.ParticleMesh; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.DepthOfFieldFilter; +import com.jme3.post.filters.FXAAFilter; +import com.jme3.post.filters.LightScatteringFilter; +import com.jme3.renderer.Camera; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.terrain.geomipmap.TerrainQuad; +import com.jme3.terrain.heightmap.AbstractHeightMap; +import com.jme3.terrain.heightmap.ImageBasedHeightMap; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.Texture2D; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; +import com.jme3.water.WaterFilter; +import java.util.ArrayList; +import java.util.List; + +/** + * test + * + * @author normenhansen + */ +public class TestPostWater extends SimpleApplication { + + private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f); + private WaterFilter water; + TerrainQuad terrain; + Material matRock; + AudioNode waves; + LowPassFilter underWaterAudioFilter = new LowPassFilter(0.5f, 0.1f); + LowPassFilter underWaterReverbFilter = new LowPassFilter(0.5f, 0.1f); + LowPassFilter aboveWaterAudioFilter = new LowPassFilter(1, 1); + + public static void main(String[] args) { + TestPostWater app = new TestPostWater(); + app.start(); + } + + @Override + public void simpleInitApp() { + + setDisplayFps(false); + setDisplayStatView(false); + + Node mainScene = new Node("Main Scene"); + rootNode.attachChild(mainScene); + + createTerrain(mainScene); + DirectionalLight sun = new DirectionalLight(); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(1f)); + mainScene.addLight(sun); + + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f)); + mainScene.addLight(al); + + flyCam.setMoveSpeed(50); + + //cam.setLocation(new Vector3f(-700, 100, 300)); + //cam.setRotation(new Quaternion().fromAngleAxis(0.5f, Vector3f.UNIT_Z)); +// cam.setLocation(new Vector3f(-327.21957f, 61.6459f, 126.884346f)); +// cam.setRotation(new Quaternion(0.052168474f, 0.9443102f, -0.18395276f, 0.2678024f)); + + + cam.setLocation(new Vector3f(-370.31592f, 182.04016f, 196.81192f)); + cam.setRotation(new Quaternion(0.015302252f, 0.9304095f, -0.039101653f, 0.3641086f)); + + + + + Spatial sky = SkyFactory.createSky(assetManager, + "Scenes/Beach/FullskiesSunset0068.dds", EnvMapType.CubeMap); + sky.setLocalScale(350); + + mainScene.attachChild(sky); + cam.setFrustumFar(4000); + + //Water Filter + water = new WaterFilter(rootNode, lightDir); + water.setWaterColor(new ColorRGBA().setAsSrgb(0.0078f, 0.3176f, 0.5f, 1.0f)); + water.setDeepWaterColor(new ColorRGBA().setAsSrgb(0.0039f, 0.00196f, 0.145f, 1.0f)); + water.setUnderWaterFogDistance(80); + water.setWaterTransparency(0.12f); + water.setFoamIntensity(0.4f); + water.setFoamHardness(0.3f); + water.setFoamExistence(new Vector3f(0.8f, 8f, 1f)); + water.setReflectionDisplace(50); + water.setRefractionConstant(0.25f); + water.setColorExtinction(new Vector3f(30, 50, 70)); + water.setCausticsIntensity(0.4f); + water.setWaveScale(0.003f); + water.setMaxAmplitude(2f); + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + water.setRefractionStrength(0.2f); + water.setWaterHeight(initialWaterHeight); + + //Bloom Filter + BloomFilter bloom = new BloomFilter(); + bloom.setExposurePower(55); + bloom.setBloomIntensity(1.0f); + + //Light Scattering Filter + LightScatteringFilter lsf = new LightScatteringFilter(lightDir.mult(-300)); + lsf.setLightDensity(0.5f); + + //Depth of field Filter + DepthOfFieldFilter dof = new DepthOfFieldFilter(); + dof.setFocusDistance(0); + dof.setFocusRange(100); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + + fpp.addFilter(water); + fpp.addFilter(bloom); + fpp.addFilter(dof); + fpp.addFilter(lsf); + fpp.addFilter(new FXAAFilter()); + +// fpp.addFilter(new TranslucentBucketFilter()); + int numSamples = getContext().getSettings().getSamples(); + if (numSamples > 0) { + fpp.setNumSamples(numSamples); + } + + + uw = cam.getLocation().y < waterHeight; + + waves = new AudioNode(assetManager, "Sound/Environment/Ocean Waves.ogg", + DataType.Buffer); + waves.setLooping(true); + waves.setReverbEnabled(true); + if (uw) { + waves.setDryFilter(new LowPassFilter(0.5f, 0.1f)); + } else { + waves.setDryFilter(aboveWaterAudioFilter); + } + audioRenderer.playSource(waves); + // + viewPort.addProcessor(fpp); + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + if (name.equals("foam1")) { + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg")); + } + if (name.equals("foam2")) { + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg")); + } + if (name.equals("foam3")) { + water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam3.jpg")); + } + + if (name.equals("upRM")) { + water.setReflectionMapSize(Math.min(water.getReflectionMapSize() * 2, 4096)); + System.out.println("Reflection map size : " + water.getReflectionMapSize()); + } + if (name.equals("downRM")) { + water.setReflectionMapSize(Math.max(water.getReflectionMapSize() / 2, 32)); + System.out.println("Reflection map size : " + water.getReflectionMapSize()); + } + } + } + }, "foam1", "foam2", "foam3", "upRM", "downRM"); + inputManager.addMapping("foam1", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("foam2", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addMapping("foam3", new KeyTrigger(KeyInput.KEY_3)); + inputManager.addMapping("upRM", new KeyTrigger(KeyInput.KEY_PGUP)); + inputManager.addMapping("downRM", new KeyTrigger(KeyInput.KEY_PGDN)); +// createBox(); +// createFire(); + } + Geometry box; + + private void createBox() { + //creating a transluscent box + box = new Geometry("box", new Box(50, 50, 50)); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", new ColorRGBA(1.0f, 0, 0, 0.3f)); + mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + //mat.getAdditionalRenderState().setDepthWrite(false); + //mat.getAdditionalRenderState().setDepthTest(false); + box.setMaterial(mat); + box.setQueueBucket(Bucket.Translucent); + + + //creating a post view port +// ViewPort post=renderManager.createPostView("transpPost", cam); +// post.setClearFlags(false, true, true); + + + box.setLocalTranslation(-600, 0, 300); + + //attaching the box to the post viewport + //Don't forget to updateGeometricState() the box in the simpleUpdate + // post.attachScene(box); + + rootNode.attachChild(box); + } + + private void createFire() { + /** + * Uses Texture from jme3-test-data library! + */ + ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30); + Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); + mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); + + fire.setMaterial(mat_red); + fire.setImagesX(2); + fire.setImagesY(2); // 2x2 texture animation + fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red + fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow + fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0)); + fire.setStartSize(10f); + fire.setEndSize(1f); + fire.setGravity(0, 0, 0); + fire.setLowLife(0.5f); + fire.setHighLife(1.5f); + fire.getParticleInfluencer().setVelocityVariation(0.3f); + fire.setLocalTranslation(-600, 50, 300); + + fire.setQueueBucket(Bucket.Translucent); + rootNode.attachChild(fire); + } + + private void createTerrain(Node rootNode) { + matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md"); + matRock.setBoolean("useTriPlanarMapping", false); + matRock.setBoolean("WardIso", true); + matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); + Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap", grass); + matRock.setFloat("DiffuseMap_0_scale", 64); + Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_1", dirt); + matRock.setFloat("DiffuseMap_1_scale", 16); + Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(WrapMode.Repeat); + matRock.setTexture("DiffuseMap_2", rock); + matRock.setFloat("DiffuseMap_2_scale", 128); + Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(WrapMode.Repeat); + Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(WrapMode.Repeat); + Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(WrapMode.Repeat); + matRock.setTexture("NormalMap", normalMap0); + matRock.setTexture("NormalMap_1", normalMap2); + matRock.setTexture("NormalMap_2", normalMap2); + + AbstractHeightMap heightmap = null; + try { + heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); + heightmap.load(); + } catch (Exception e) { + e.printStackTrace(); + } + terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap()); + List cameras = new ArrayList(); + cameras.add(getCamera()); + terrain.setMaterial(matRock); + terrain.setLocalScale(new Vector3f(5, 5, 5)); + terrain.setLocalTranslation(new Vector3f(0, -30, 0)); + terrain.setLocked(false); // unlock it so we can edit the height + + terrain.setShadowMode(ShadowMode.Receive); + rootNode.attachChild(terrain); + + } + //This part is to emulate tides, slightly varrying the height of the water plane + private float time = 0.0f; + private float waterHeight = 0.0f; + private float initialWaterHeight = 90f;//0.8f; + private boolean uw = false; + + @Override + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + // box.updateGeometricState(); + time += tpf; + waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f; + water.setWaterHeight(initialWaterHeight + waterHeight); + if (water.isUnderWater() && !uw) { + + waves.setDryFilter(new LowPassFilter(0.5f, 0.1f)); + uw = true; + } + if (!water.isUnderWater() && uw) { + uw = false; + //waves.setReverbEnabled(false); + waves.setDryFilter(new LowPassFilter(1, 1f)); + //waves.setDryFilter(new LowPassFilter(1,1f)); + + } + } +} diff --git a/JmeTests/src/jme3test/water/TestPostWaterLake.java b/JmeTests/src/jme3test/water/TestPostWaterLake.java new file mode 100644 index 0000000..1644102 --- /dev/null +++ b/JmeTests/src/jme3test/water/TestPostWaterLake.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.scene.Spatial; +import com.jme3.util.SkyFactory; +import com.jme3.water.WaterFilter; +import java.io.File; + +public class TestPostWaterLake extends SimpleApplication { + + // set default for applets + private static boolean useHttp = true; + + public static void main(String[] args) { + + TestPostWaterLake app = new TestPostWaterLake(); + app.start(); + } + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(-27.0f, 1.0f, 75.0f)); + // cam.setRotation(new Quaternion(0.03f, 0.9f, 0f, 0.4f)); + + // load sky + rootNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + + File file = new File("wildhouse.zip"); + + if (file.exists()) { + useHttp = false; + } + // create the geometry and attach it + // load the level from zip or http zip + if (useHttp) { + assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip", HttpZipLocator.class); + } else { + assetManager.registerLocator("wildhouse.zip", ZipLocator.class); + } + Spatial scene = assetManager.loadModel("main.scene"); + rootNode.attachChild(scene); + + DirectionalLight sun = new DirectionalLight(); + Vector3f lightDir = new Vector3f(-0.37352666f, -0.50444174f, -0.7784704f); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + scene.addLight(sun); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + final WaterFilter water = new WaterFilter(rootNode, lightDir); + water.setWaterHeight(-20); + water.setUseFoam(false); + water.setUseRipples(false); + water.setDeepWaterColor(ColorRGBA.Brown); + water.setWaterColor(ColorRGBA.Brown.mult(2.0f)); + water.setWaterTransparency(0.2f); + water.setMaxAmplitude(0.3f); + water.setWaveScale(0.008f); + water.setSpeed(0.7f); + water.setShoreHardness(1.0f); + water.setRefractionConstant(0.2f); + water.setShininess(0.3f); + water.setSunScale(1.0f); + water.setColorExtinction(new Vector3f(10.0f, 20.0f, 30.0f)); + fpp.addFilter(water); + viewPort.addProcessor(fpp); + + inputManager.addListener(new ActionListener() { + + public void onAction(String name, boolean isPressed, float tpf) { + if(isPressed){ + if(water.isUseHQShoreline()){ + water.setUseHQShoreline(false); + }else{ + water.setUseHQShoreline(true); + } + } + } + }, "HQ"); + + inputManager.addMapping("HQ", new KeyTrigger(keyInput.KEY_SPACE)); + } +} diff --git a/JmeTests/src/jme3test/water/TestSceneWater.java b/JmeTests/src/jme3test/water/TestSceneWater.java new file mode 100644 index 0000000..4e0d8d6 --- /dev/null +++ b/JmeTests/src/jme3test/water/TestSceneWater.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.plugins.HttpZipLocator; +import com.jme3.asset.plugins.ZipLocator; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.SkyFactory; +import com.jme3.water.SimpleWaterProcessor; +import java.io.File; + +public class TestSceneWater extends SimpleApplication { + + // set default for applets + private static boolean useHttp = true; + + public static void main(String[] args) { + + TestSceneWater app = new TestSceneWater(); + app.start(); + } + + public void simpleInitApp() { + this.flyCam.setMoveSpeed(10); + Node mainScene=new Node(); + cam.setLocation(new Vector3f(-27.0f, 1.0f, 75.0f)); + cam.setRotation(new Quaternion(0.03f, 0.9f, 0f, 0.4f)); + + // load sky + mainScene.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + + + File file = new File("wildhouse.zip"); + if (file.exists()) { + useHttp = false; + } + // create the geometry and attach it + // load the level from zip or http zip + if (useHttp) { + assetManager.registerLocator("https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/wildhouse.zip", HttpZipLocator.class); + } else { + assetManager.registerLocator("wildhouse.zip", ZipLocator.class); + } + Spatial scene = assetManager.loadModel("main.scene"); + + DirectionalLight sun = new DirectionalLight(); + Vector3f lightDir=new Vector3f(-0.37352666f, -0.50444174f, -0.7784704f); + sun.setDirection(lightDir); + sun.setColor(ColorRGBA.White.clone().multLocal(2)); + scene.addLight(sun); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + //add lightPos Geometry + Sphere lite=new Sphere(8, 8, 3.0f); + Geometry lightSphere=new Geometry("lightsphere", lite); + lightSphere.setMaterial(mat); + Vector3f lightPos=lightDir.multLocal(-400); + lightSphere.setLocalTranslation(lightPos); + rootNode.attachChild(lightSphere); + + + SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager); + waterProcessor.setReflectionScene(mainScene); + waterProcessor.setDebug(false); + waterProcessor.setLightPosition(lightPos); + waterProcessor.setRefractionClippingOffset(1.0f); + + + //setting the water plane + Vector3f waterLocation=new Vector3f(0,-20,0); + waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y))); + WaterUI waterUi=new WaterUI(inputManager, waterProcessor); + waterProcessor.setWaterColor(ColorRGBA.Brown); + waterProcessor.setDebug(true); + //lower render size for higher performance +// waterProcessor.setRenderSize(128,128); + //raise depth to see through water +// waterProcessor.setWaterDepth(20); + //lower the distortion scale if the waves appear too strong +// waterProcessor.setDistortionScale(0.1f); + //lower the speed of the waves if they are too fast +// waterProcessor.setWaveSpeed(0.01f); + + Quad quad = new Quad(400,400); + + //the texture coordinates define the general size of the waves + quad.scaleTextureCoordinates(new Vector2f(6f,6f)); + + Geometry water=new Geometry("water", quad); + water.setShadowMode(ShadowMode.Receive); + water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X)); + water.setMaterial(waterProcessor.getMaterial()); + water.setLocalTranslation(-200, -20, 250); + + rootNode.attachChild(water); + + viewPort.addProcessor(waterProcessor); + + mainScene.attachChild(scene); + rootNode.attachChild(mainScene); + } +} diff --git a/JmeTests/src/jme3test/water/TestSimpleWater.java b/JmeTests/src/jme3test/water/TestSimpleWater.java new file mode 100644 index 0000000..c8ba06f --- /dev/null +++ b/JmeTests/src/jme3test/water/TestSimpleWater.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.water; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.util.SkyFactory; +import com.jme3.water.SimpleWaterProcessor; + +/** + * + * @author normenhansen + */ +public class TestSimpleWater extends SimpleApplication implements ActionListener { + + Material mat; + Spatial waterPlane; + Geometry lightSphere; + SimpleWaterProcessor waterProcessor; + Node sceneNode; + boolean useWater = true; + private Vector3f lightPos = new Vector3f(33,12,-29); + + + public static void main(String[] args) { + TestSimpleWater app = new TestSimpleWater(); + app.start(); + } + + @Override + public void simpleInitApp() { + initInput(); + initScene(); + + //create processor + waterProcessor = new SimpleWaterProcessor(assetManager); + waterProcessor.setReflectionScene(sceneNode); + waterProcessor.setDebug(true); + viewPort.addProcessor(waterProcessor); + + waterProcessor.setLightPosition(lightPos); + + //create water quad + //waterPlane = waterProcessor.createWaterGeometry(100, 100); + waterPlane=(Spatial) assetManager.loadModel("Models/WaterTest/WaterTest.mesh.xml"); + waterPlane.setMaterial(waterProcessor.getMaterial()); + waterPlane.setLocalScale(40); + waterPlane.setLocalTranslation(-5, 0, 5); + + rootNode.attachChild(waterPlane); + } + + private void initScene() { + //init cam location + cam.setLocation(new Vector3f(0, 10, 10)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + //init scene + sceneNode = new Node("Scene"); + mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg")); + Box b = new Box(1, 1, 1); + Geometry geom = new Geometry("Box", b); + geom.setMaterial(mat); + sceneNode.attachChild(geom); + + // load sky + sceneNode.attachChild(SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/BrightSky.dds", + SkyFactory.EnvMapType.CubeMap)); + rootNode.attachChild(sceneNode); + + //add lightPos Geometry + Sphere lite=new Sphere(8, 8, 3.0f); + lightSphere=new Geometry("lightsphere", lite); + lightSphere.setMaterial(mat); + lightSphere.setLocalTranslation(lightPos); + rootNode.attachChild(lightSphere); + } + + protected void initInput() { + flyCam.setMoveSpeed(3); + //init input + inputManager.addMapping("use_water", new KeyTrigger(KeyInput.KEY_O)); + inputManager.addListener(this, "use_water"); + inputManager.addMapping("lightup", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addListener(this, "lightup"); + inputManager.addMapping("lightdown", new KeyTrigger(KeyInput.KEY_G)); + inputManager.addListener(this, "lightdown"); + inputManager.addMapping("lightleft", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addListener(this, "lightleft"); + inputManager.addMapping("lightright", new KeyTrigger(KeyInput.KEY_K)); + inputManager.addListener(this, "lightright"); + inputManager.addMapping("lightforward", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addListener(this, "lightforward"); + inputManager.addMapping("lightback", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addListener(this, "lightback"); + } + + @Override + public void simpleUpdate(float tpf) { + fpsText.setText("Light Position: "+lightPos.toString()+" Change Light position with [U], [H], [J], [K] and [T], [G] Turn off water with [O]"); + lightSphere.setLocalTranslation(lightPos); + waterProcessor.setLightPosition(lightPos); + } + + public void onAction(String name, boolean value, float tpf) { + if (name.equals("use_water") && value) { + if (!useWater) { + useWater = true; + waterPlane.setMaterial(waterProcessor.getMaterial()); + } else { + useWater = false; + waterPlane.setMaterial(mat); + } + } else if (name.equals("lightup") && value) { + lightPos.y++; + } else if (name.equals("lightdown") && value) { + lightPos.y--; + } else if (name.equals("lightleft") && value) { + lightPos.x--; + } else if (name.equals("lightright") && value) { + lightPos.x++; + } else if (name.equals("lightforward") && value) { + lightPos.z--; + } else if (name.equals("lightback") && value) { + lightPos.z++; + } + } +} diff --git a/JmeTests/src/jme3test/water/WaterUI.java b/JmeTests/src/jme3test/water/WaterUI.java new file mode 100644 index 0000000..c097320 --- /dev/null +++ b/JmeTests/src/jme3test/water/WaterUI.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jme3test.water; + +import com.jme3.input.InputManager; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.water.SimpleWaterProcessor; + +/** + * + * @author nehon + */ +public class WaterUI { + private SimpleWaterProcessor processor; + public WaterUI(InputManager inputManager, SimpleWaterProcessor proc) { + processor=proc; + + + System.out.println("----------------- SSAO UI Debugger --------------------"); + System.out.println("-- Water transparency : press Y to increase, H to decrease"); + System.out.println("-- Water depth : press U to increase, J to decrease"); +// System.out.println("-- AO scale : press I to increase, K to decrease"); +// System.out.println("-- AO bias : press O to increase, P to decrease"); +// System.out.println("-- Toggle AO on/off : press space bar"); +// System.out.println("-- Use only AO : press Num pad 0"); +// System.out.println("-- Output config declaration : press P"); + System.out.println("-------------------------------------------------------"); + + inputManager.addMapping("transparencyUp", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("transparencyDown", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("depthUp", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("depthDown", new KeyTrigger(KeyInput.KEY_J)); +// inputManager.addMapping("scaleUp", new KeyTrigger(KeyInput.KEY_I)); +// inputManager.addMapping("scaleDown", new KeyTrigger(KeyInput.KEY_K)); +// inputManager.addMapping("biasUp", new KeyTrigger(KeyInput.KEY_O)); +// inputManager.addMapping("biasDown", new KeyTrigger(KeyInput.KEY_L)); +// inputManager.addMapping("outputConfig", new KeyTrigger(KeyInput.KEY_P)); +// inputManager.addMapping("toggleUseAO", new KeyTrigger(KeyInput.KEY_SPACE)); +// inputManager.addMapping("toggleUseOnlyAo", new KeyTrigger(KeyInput.KEY_NUMPAD0)); + +// ActionListener acl = new ActionListener() { +// +// public void onAction(String name, boolean keyPressed, float tpf) { +// +// if (name.equals("toggleUseAO") && keyPressed) { +// ssaoConfig.setUseAo(!ssaoConfig.isUseAo()); +// System.out.println("use AO : "+ssaoConfig.isUseAo()); +// } +// if (name.equals("toggleUseOnlyAo") && keyPressed) { +// ssaoConfig.setUseOnlyAo(!ssaoConfig.isUseOnlyAo()); +// System.out.println("use Only AO : "+ssaoConfig.isUseOnlyAo()); +// +// } +// if (name.equals("outputConfig") && keyPressed) { +// System.out.println("new SSAOConfig("+ssaoConfig.getSampleRadius()+"f,"+ssaoConfig.getIntensity()+"f,"+ssaoConfig.getScale()+"f,"+ssaoConfig.getBias()+"f,"+ssaoConfig.isUseOnlyAo()+","+ssaoConfig.isUseAo()+");"); +// } +// +// } +// }; + + AnalogListener anl = new AnalogListener() { + + public void onAnalog(String name, float value, float tpf) { + if (name.equals("transparencyUp")) { + processor.setWaterTransparency(processor.getWaterTransparency()+0.001f); + System.out.println("Water transparency : "+processor.getWaterTransparency()); + } + if (name.equals("transparencyDown")) { + processor.setWaterTransparency(processor.getWaterTransparency()-0.001f); + System.out.println("Water transparency : "+processor.getWaterTransparency()); + } + if (name.equals("depthUp")) { + processor.setWaterDepth(processor.getWaterDepth()+0.001f); + System.out.println("Water depth : "+processor.getWaterDepth()); + } + if (name.equals("depthDown")) { + processor.setWaterDepth(processor.getWaterDepth()-0.001f); + System.out.println("Water depth : "+processor.getWaterDepth()); + } + + } + }; + // inputManager.addListener(acl,"toggleUseAO","toggleUseOnlyAo","outputConfig"); + inputManager.addListener(anl, "transparencyUp","transparencyDown","depthUp","depthDown"); + + } + + + +} diff --git a/SigDN/MANIFEST.MF b/SigDN/MANIFEST.MF new file mode 100644 index 0000000..7e1ad4b --- /dev/null +++ b/SigDN/MANIFEST.MF @@ -0,0 +1 @@ +X-Comment: Created with jMonkeyPlatform diff --git a/SigDN/OpenAL64.dll b/SigDN/OpenAL64.dll new file mode 100644 index 0000000..6f2a2fe Binary files /dev/null and b/SigDN/OpenAL64.dll differ diff --git a/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3o b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3o new file mode 100644 index 0000000..7de6419 Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3o differ diff --git a/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3odata b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3odata new file mode 100644 index 0000000..6dcbcb7 --- /dev/null +++ b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.j3odata @@ -0,0 +1,3 @@ +# +#Thu Jun 13 01:11:59 KST 2019 +ORIGINAL_PATH=Models/Archer_finalrig/Archer_finalrig.obj diff --git a/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3o b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3o new file mode 100644 index 0000000..c674070 Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3o differ diff --git a/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3odata b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3odata new file mode 100644 index 0000000..c0a0dc6 --- /dev/null +++ b/SigDN/assets/Models/Archer_finalrig/Archer_finalrig.mesh.j3odata @@ -0,0 +1,3 @@ +# +#Thu Jun 13 01:32:08 KST 2019 +ORIGINAL_PATH=Models/Archer_finalrig/Archer_finalrig.mesh.xml diff --git a/SigDN/assets/Models/Archer_finalrig/ar_hair01_yellow.png b/SigDN/assets/Models/Archer_finalrig/ar_hair01_yellow.png new file mode 100644 index 0000000..d607851 Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_hair01_yellow.png differ diff --git a/SigDN/assets/Models/Archer_finalrig/ar_head01.png b/SigDN/assets/Models/Archer_finalrig/ar_head01.png new file mode 100644 index 0000000..cb27b3e Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_head01.png differ diff --git a/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_body.png b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_body.png new file mode 100644 index 0000000..babdbbf Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_body.png differ diff --git a/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_boots.png b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_boots.png new file mode 100644 index 0000000..9ca1053 Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_boots.png differ diff --git a/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_glove.png b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_glove.png new file mode 100644 index 0000000..98d7fb6 Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_glove.png differ diff --git a/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_leg.png.png b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_leg.png.png new file mode 100644 index 0000000..c34f52f Binary files /dev/null and b/SigDN/assets/Models/Archer_finalrig/ar_ropie_d01_leg.png.png differ diff --git a/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3o b/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3o new file mode 100644 index 0000000..c067b48 Binary files /dev/null and b/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3o differ diff --git a/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3odata b/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3odata new file mode 100644 index 0000000..2c056f6 --- /dev/null +++ b/SigDN/assets/Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3odata @@ -0,0 +1,3 @@ +# +#Thu Jun 13 02:01:43 KST 2019 +ORIGINAL_PATH=Models/Smallbow_Mimiyala/Smallbow_Mimiyala.obj diff --git a/SigDN/assets/Models/Smallbow_Mimiyala/ar_smallbow_mimiyala_d02.dds.png b/SigDN/assets/Models/Smallbow_Mimiyala/ar_smallbow_mimiyala_d02.dds.png new file mode 100644 index 0000000..0870697 Binary files /dev/null and b/SigDN/assets/Models/Smallbow_Mimiyala/ar_smallbow_mimiyala_d02.dds.png differ diff --git a/SigDN/build.xml b/SigDN/build.xml new file mode 100644 index 0000000..01bd9fe --- /dev/null +++ b/SigDN/build.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + Builds, tests, and runs the project BasicGameTemplate. + + + + + diff --git a/SigDN/bulletjme.dll b/SigDN/bulletjme.dll new file mode 100644 index 0000000..fb9034a Binary files /dev/null and b/SigDN/bulletjme.dll differ diff --git a/SigDN/lwjgl64.dll b/SigDN/lwjgl64.dll new file mode 100644 index 0000000..2c8b93e Binary files /dev/null and b/SigDN/lwjgl64.dll differ diff --git a/SigDN/master-application.jnlp b/SigDN/master-application.jnlp new file mode 100644 index 0000000..49cbb12 --- /dev/null +++ b/SigDN/master-application.jnlp @@ -0,0 +1,22 @@ + + + ${APPLICATION.TITLE} + ${APPLICATION.VENDOR} + + ${APPLICATION.DESC} + ${APPLICATION.DESC.SHORT} + + + + + + + + + + + + + + + diff --git a/SigDN/nbproject/assets-impl.xml b/SigDN/nbproject/assets-impl.xml new file mode 100644 index 0000000..0a47d8d --- /dev/null +++ b/SigDN/nbproject/assets-impl.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/SigDN/nbproject/build-impl.xml b/SigDN/nbproject/build-impl.xml new file mode 100644 index 0000000..283b780 --- /dev/null +++ b/SigDN/nbproject/build-impl.xml @@ -0,0 +1,1404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SigDN/nbproject/genfiles.properties b/SigDN/nbproject/genfiles.properties new file mode 100644 index 0000000..a341038 --- /dev/null +++ b/SigDN/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=94bf7c61 +build.xml.script.CRC32=79a29eb7 +build.xml.stylesheet.CRC32=958a1d3e@1.32.1.45 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=955cd37c +nbproject/build-impl.xml.script.CRC32=e1a6370b +nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48 diff --git a/SigDN/nbproject/project.properties b/SigDN/nbproject/project.properties new file mode 100644 index 0000000..a44144e --- /dev/null +++ b/SigDN/nbproject/project.properties @@ -0,0 +1,92 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +application.title=MyGame +application.vendor=MyCompany +assets.jar.name=assets.jar +assets.excludes=**/*.j3odata,**/*.mesh,**/*.skeleton,**/*.mesh\.xml,**/*.skeleton\.xml,**/*.scene,**/*.material,**/*.obj,**/*.mtl,**/*.3ds,**/*.dae,**/*.blend,**/*.blend*[0-9] +assets.folder.name=assets +assets.compress=true +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +compile.on.save=true +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/${application.title}.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +includes=** +jar.compress=false +javac.classpath=\ + ${libs.jme3-jogg.classpath}:\ + ${libs.jme3-networking.classpath}:\ + ${libs.jme3-plugins.classpath}:\ + ${libs.jme3-core.classpath}:\ + ${libs.jme3-desktop.classpath}:\ + ${libs.jme3-lwjgl.classpath}:\ + ${libs.jme3-effects.classpath}:\ + ${libs.jme3-terrain.classpath}:\ + ${libs.jme3-bullet.classpath}:\ + ${libs.jme3-bullet-native.classpath} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.7 +javac.target=1.7 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api" +jme.project.version=3.1 +jnlp.codebase.type=local +jnlp.descriptor=application +jnlp.enabled=false +jnlp.offline-allowed=false +jnlp.signed=false +main.class=mygame.Main +meta.inf.dir=${src.dir}/META-INF +manifest.file=MANIFEST.MF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${assets.folder.name} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src diff --git a/SigDN/nbproject/project.xml b/SigDN/nbproject/project.xml new file mode 100644 index 0000000..13267c4 --- /dev/null +++ b/SigDN/nbproject/project.xml @@ -0,0 +1,18 @@ + + + org.netbeans.modules.java.j2seproject + + + + + + + + SigDN + + + + + + + diff --git a/SigDN/src/mygame/Main.java b/SigDN/src/mygame/Main.java new file mode 100644 index 0000000..88840da --- /dev/null +++ b/SigDN/src/mygame/Main.java @@ -0,0 +1,119 @@ +package mygame; + +import com.jme3.animation.AnimChannel; +import com.jme3.animation.AnimControl; +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.animation.*; +import com.jme3.input.controls.ActionListener; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.scene.Node; + +/** + * This is the Main Class of your Game. You should only do initialization here. + * Move your Logic into AppStates or Controls + * @author normenhansen + */ +public class Main extends SimpleApplication implements + AnimEventListener,ActionListener{ + private AnimChannel channel; + private AnimControl control; + private Geometry geom; + + public static void main(String[] args) { + Main app = new Main(); + app.start(); + } + + @Override + public void simpleInitApp() { + + flyCam.setMoveSpeed(20f); + flyCam.setZoomSpeed(20f); + cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f)); + cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f)); + + // sunset light + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal()); + dl.setColor(new ColorRGBA(1f, 1f, 1f, 0.5f)); + rootNode.addLight(dl); + DirectionalLight dl2 = new DirectionalLight(); + dl2.setColor(new ColorRGBA(1f, 1f, 1f, 0.5f)); + dl2.setDirection(new Vector3f(0.1f, -0.7f, -1).normalizeLocal()); + rootNode.addLight(dl2); + Spatial Archer = (Spatial) assetManager.loadModel("Models/Archer_finalrig/Archer_finalrig.mesh.j3o"); + float scale = 0.05f; + Archer.scale(scale, scale, scale); + + Spatial bow = (Spatial) assetManager.loadModel("Models/Smallbow_Mimiyala/Smallbow_Mimiyala.j3o"); + + + control = Archer.getControl(AnimControl.class); + control.addListener(this); + channel = control.createChannel(); + + for (String anim : control.getAnimationNames()) + System.out.println(anim); + + channel.setAnim("Idle Animation"); + geom = (Geometry)((Node)Archer).getChild(0); + SkeletonControl skeletonControl = Archer.getControl(SkeletonControl.class); + + Node n = skeletonControl.getAttachmentsNode("Torso"); + bow.setLocalTranslation(5.7983f,2.0104f,12.5006f); + //bow.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.PI*1f/4, new Vector3f(1,0,0))); + bow.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.PI*1f/4, new Vector3f(1,0,0)).mult( + new Quaternion().fromAngleAxis(FastMath.PI*3f/2, new Vector3f(0,1,0)))); + //n.set + n.attachChild(bow); + //n.setLocalTranslation(5.7983f,99.0104f,12.5006f); + for (Spatial s : n.getChildren()) { + System.out.println(s.getName()); + //System.out.println(s.getLocalTransform()); + System.out.println(s.getWorldTransform()); + } + + rootNode.attachChild(Archer); + //rootNode.attachChild(bow); + } + + @Override + public void simpleUpdate(float tpf) { + //TODO: add update code + } + + @Override + public void simpleRender(RenderManager rm) { + //TODO: add render code + } + + public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { + if (animName.equals("Dodge")){ + channel.setAnim("stand", 0.50f); + channel.setLoopMode(LoopMode.DontLoop); + channel.setSpeed(1f); + } + } + + public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { + } + + public void onAction(String binding, boolean value, float tpf) { + if (binding.equals("Attack") && value){ + if (!channel.getAnimationName().equals("Dodge")){ + channel.setAnim("Dodge", 0.50f); + channel.setLoopMode(LoopMode.Cycle); + channel.setSpeed(0.10f); + } + } + } +} diff --git a/Smallbow_Mimiyala.wings b/Smallbow_Mimiyala.wings new file mode 100644 index 0000000..8945108 Binary files /dev/null and b/Smallbow_Mimiyala.wings differ diff --git a/Weapons/Smallbow_Mimiyala.mtl b/Weapons/Smallbow_Mimiyala.mtl new file mode 100644 index 0000000..67d2ff0 --- /dev/null +++ b/Weapons/Smallbow_Mimiyala.mtl @@ -0,0 +1,11 @@ +# Exported from Wings 3D 2.2.4 +newmtl default +Ns 19.999999999999996 +d 1.0 +illum 2 +Kd 0.7898538076923077 0.8133333333333334 0.6940444444444445 +Ka 0.0 0.0 0.0 +Ks 0.1689853807692308 0.17133333333333334 0.15940444444444446 +Ke 0.0 0.0 0.0 +map_Kd ar_smallbow_mimiyala_d02.dds.png + diff --git a/Weapons/Smallbow_Mimiyala.obj b/Weapons/Smallbow_Mimiyala.obj new file mode 100644 index 0000000..307b119 --- /dev/null +++ b/Weapons/Smallbow_Mimiyala.obj @@ -0,0 +1,2753 @@ +# Exported from Wings 3D 2.2.4 +mtllib Smallbow_Mimiyala.mtl +o Ar_SmallBow_mimiyala_D +#592 vertices, 1104 faces +v 2.6520000e-2 12.63921300 26.85111000 +v -3.0000000e-5 12.08854100 -4.0912000e-2 +v -8.0000000e-5 12.32410700 -4.7163000e-2 +v 0.79115000 13.77120100 26.94543500 +v -8.7500000e-4 14.25949500 26.71108200 +v -7.4700000e-4 13.44757300 26.21382100 +v -0.79266400 13.77087700 26.94555700 +v 0.78629200 13.70282200 28.17181600 +v -6.6100000e-4 13.41059200 27.24888600 +v 0.77156900 12.77224600 26.55572900 +v -6.0600000e-4 12.73207400 26.14708900 +v -0.77273500 12.77193100 26.55584700 +v -0.78759200 13.70250000 28.17193400 +v -6.0500000e-4 13.33600700 27.78041500 +v -0.73381100 11.26282500 27.46922300 +v -3.2300000e-4 11.73283800 27.18208300 +v -0.68741200 10.32901600 25.87927800 +v -1.1400000e-4 9.76286900 24.64081200 +v -0.65398000 7.76496700 24.18670700 +v 1.1300000e-4 8.17934400 23.37687300 +v -0.61875200 4.69229100 21.06013500 +v 0.73340200 11.26312400 27.46911000 +v 0.68714100 10.32929700 25.87917300 +v 0.65452900 7.65530200 24.28964200 +v 0.61972400 4.69248100 21.06006400 +v 5.8400000e-4 6.32986300 24.59074400 +v 3.6000000e-4 7.95267200 26.00191300 +v -3.0000000e-4 12.16023300 28.62651800 +v 2.6000000e-5 10.31189900 27.94780200 +v 2.5000000e-5 9.72854600 26.36921500 +v -0.66048300 9.12994300 26.17107000 +v 1.3700000e-4 9.37682000 26.89381400 +v 0.66074700 9.13021300 26.17096900 +v -6.0800000e-4 13.68656000 28.67319100 +v 4.4000000e-5 9.77682300 26.74627300 +v 3.5000000e-5 10.00225400 27.22833600 +v -8.4800000e-4 14.58861100 27.94562100 +v -0.49025500 -1.47705000 -2.01839100 +v -1.0000000e-6 -0.77859200 -1.22468300 +v -0.45694300 -2.24575700 -2.1810000e-2 +v -1.0000000e-6 -1.39048200 -2.5869000e-2 +v 0.45694100 -2.24575700 -2.1810000e-2 +v 0.49025400 -1.47705000 -2.01839100 +v -1.0000000e-6 -3.14903000 -1.0307000e-2 +v 0.44341800 -2.20286200 -2.42332500 +v 0.73101700 0.55036800 -2.88085500 +v -1.0000000e-6 0.55933800 -3.99140500 +v 0.77919900 3.01416200 -2.17355800 +v -1.0000000e-6 3.54545100 -2.66930200 +v -1.0000000e-6 4.11075800 1.3362000e-2 +v -0.77920000 3.01416200 -2.17355800 +v -0.73101900 0.55036800 -2.88085500 +v -0.44341900 -2.20286200 -2.42332500 +v -1.0000000e-6 0.54359000 -1.86437800 +v -1.0000000e-6 2.08809000 -1.53155600 +v 0.85430700 3.40059400 2.1478000e-2 +v -1.0000000e-6 3.62609500 2.65755000 +v 0.83391000 2.96569300 2.02581700 +v 0.60856400 0.74531100 4.06687900 +v 0.54934400 0.75386700 3.16537500 +v 0.55638100 -0.20517100 3.99068600 +v 0.47533400 -1.28099600 2.49639000 +v -0.85430800 3.40058900 2.1288000e-2 +v -0.83391200 2.96543300 2.01616600 +v -0.60856500 0.74495900 4.05380400 +v -0.54934600 0.75361900 3.15618600 +v -0.55638200 -0.20545800 3.98004500 +v -0.47533500 -1.28110900 2.49220800 +v -1.0000000e-6 -2.12207700 3.21196300 +v -1.0000000e-6 -0.55410200 4.06854500 +v -1.0000000e-6 -0.64716400 1.72147600 +v -1.0000000e-6 0.76384400 2.07056500 +v -1.0000000e-6 2.12193000 1.42018900 +v -1.0000000e-6 2.23398900 3.7198000e-2 +v 0.72763100 5.29848400 -10.02118200 +v 0.71532800 4.92659200 -7.99716000 +v 4.0000000e-6 5.76790300 -9.62562800 +v 1.0000000e-6 5.54512300 -8.00400400 +v -0.71532600 4.92659200 -7.99716000 +v -0.72762300 5.29848500 -10.02118200 +v 4.0000000e-6 5.72381700 -10.54713200 +v -0.72000700 4.68652500 -11.32914800 +v 4.0000000e-6 5.02715500 -11.62779900 +v 3.0000000e-6 4.08617900 -11.79677700 +v -0.69891100 3.82730100 -10.72662000 +v 2.0000000e-6 3.39066000 -11.24906900 +v 2.0000000e-6 3.35981300 -10.32820700 +v 0.69891600 3.82730000 -10.72662000 +v 0.72001400 4.68652400 -11.32914800 +v 4.0000000e-6 4.90528500 -9.91369200 +v 3.0000000e-6 4.61998900 -10.83765300 +v 3.0000000e-6 4.14882600 -10.57131400 +v 3.0000000e-6 4.16703400 -9.82717700 +v 1.0000000e-6 4.47360300 -8.09501300 +v -0.69456800 4.17034000 -6.49742300 +v 0.69456600 4.17034000 -6.49742300 +v -1.0000000e-6 4.94638400 -6.34989300 +v 0.47381900 -5.20263800 1.01625600 +v 0.53010000 -3.11521000 -3.58755500 +v 0.63567900 1.05909300 -4.99925800 +v -1.0000000e-6 1.32768900 -6.13310200 +v 0.66429400 2.74522700 -5.56317500 +v -1.0000000e-6 2.23764000 -6.66507800 +v -1.0000000e-6 3.68190200 -7.00455500 +v -0.66429600 2.74522700 -5.56317500 +v -0.63568000 1.05909300 -4.99925800 +v -0.53010200 -3.11521000 -3.58755500 +v -0.58254700 -1.28604400 -8.08695900 +v 0.47344900 -5.08481100 3.10143400 +v -1.0000000e-6 -3.95550500 3.47039800 +v -1.0000000e-6 -4.45043400 7.40355800 +v -0.47345000 -5.08481100 3.10143400 +v -0.47382100 -5.20263800 1.01625600 +v -1.0000000e-6 3.17517900 -4.57923900 +v -1.0000000e-6 4.55329000 -5.76745700 +v -0.70908200 4.88536000 -5.99279100 +v 0.70908100 4.88536000 -5.99279100 +v -1.0000000e-6 5.27326600 -6.02292100 +v -1.0000000e-6 5.10168600 -5.37447400 +v -1.0000000e-6 4.84841600 -5.71287200 +v 2.7000000e-5 6.29201600 -15.51865400 +v 0.77029600 5.75963700 -16.01831100 +v 2.3000000e-5 5.32695200 -15.74966500 +v 0.73717400 4.24436200 -15.92331800 +v 2.3000000e-5 5.45162100 -16.33560200 +v -0.77024700 5.75964400 -16.01831100 +v 1.9000000e-5 4.50125900 -16.40976300 +v -0.73713700 4.24436900 -15.92331800 +v -0.67463900 1.48041700 -14.75970800 +v 1.5000000e-5 3.44988500 -15.14335900 +v 1.9000000e-5 4.43331200 -15.59054200 +v -0.78745300 6.62586500 -15.64045000 +v 2.7000000e-5 6.16540100 -15.22798300 +v 2.8000000e-5 6.57814600 -14.99854800 +v 0.78751000 6.62585700 -15.64045000 +v 2.7000000e-5 6.20996300 -16.19869600 +v 0.67465000 1.48041100 -14.75970800 +v 9.0000000e-6 2.17658900 -14.19427500 +v 1.1000000e-5 2.60156000 -13.63629000 +v 0.62978300 0.47258200 -12.58144000 +v 0.0000000e+0 0.12351900 -15.47641000 +v 5.0000000e-6 1.27663400 -16.31470900 +v -0.62978200 0.47258500 -12.58144000 +v 3.0000000e-5 6.85654800 -15.89573900 +v 3.0000000e-5 6.99151300 -15.37170500 +v -1.0000000e-6 -2.27723600 -11.03038900 +v 0.58254500 -1.28604400 -8.08695900 +v -5.0000000e-6 -1.68097700 -13.22247700 +v -2.0000000e-6 -0.35442000 -15.00165800 +v 5.0000000e-6 1.96983000 -11.49640300 +v 0.0000000e+0 1.15397100 -9.62258000 +v -0.68169300 1.13275000 -8.75170700 +v 0.0000000e+0 1.92224800 -8.06024100 +v 0.0000000e+0 2.46701100 -8.85566600 +v 0.68169300 1.13275000 -8.75170700 +v -1.0000000e-6 -3.31790100 -7.37254400 +v 0.0000000e+0 1.84660600 -9.96145500 +v 0.0000000e+0 2.85056600 -9.93238600 +v 0.47532500 -5.64024700 7.29070600 +v -1.0000000e-6 -6.06522300 4.54724100 +v 0.44140500 -6.54715800 2.94607500 +v -1.0000000e-6 -6.46828700 1.05361700 +v -1.0000000e-6 -5.75634600 -2.26714800 +v -1.0000000e-6 -4.35591600 -4.92681600 +v -0.44140600 -6.54715800 2.94607500 +v -0.47532600 -5.64033100 7.28759400 +v 0.48003000 -5.05459300 9.97349700 +v 2.4800000e-4 -5.93961500 10.16340900 +v 0.46404000 -5.48112400 10.43540800 +v 6.6700000e-4 -5.75046200 12.57470700 +v 0.46418400 -5.03805400 13.04928800 +v 6.4100000e-4 -4.84716500 13.94227800 +v 5.4000000e-4 -3.10374600 14.37496500 +v -0.46291900 -5.03824300 13.04452900 +v -0.46356200 -5.48127400 10.43077600 +v -0.47959000 -4.81345200 9.83037700 +v 2.2700000e-4 -5.04678800 10.33203300 +v 1.9500000e-4 -3.42630800 11.39280700 +v 5.9600000e-4 -4.62048000 12.64708700 +v 1.9800000e-4 -4.28223400 9.38800100 +v -0.49183700 -2.87861800 13.80274000 +v 5.0200000e-4 -2.79470000 13.60569800 +v 0.49286200 -2.87829500 13.81231800 +v 5.0300000e-4 -2.51380200 14.37982700 +v -0.50450100 -2.41096500 13.64260500 +v 4.5300000e-4 -2.59118700 12.09958500 +v 0.50545900 -2.41059700 13.65381100 +v 4.6100000e-4 -2.01131900 13.96896600 +v 4.5100000e-4 -2.06254700 13.40545700 +v -4.8900000e-4 12.29832600 26.51381300 +v -4.3800000e-4 12.30433800 27.20151300 +v -5.4500000e-4 12.90072800 27.39092600 +v 5.4000000e-5 11.01759700 -26.32796100 +v -0.97688700 9.92816400 -26.90565700 +v 5.3000000e-5 10.84640700 -27.13758900 +v 4.9000000e-5 9.91253800 -28.22530200 +v 0.97698500 9.92815200 -26.90565700 +v 4.5000000e-5 9.22789800 -26.73297900 +v -0.98113400 10.04743000 -24.62956200 +v -1.00902400 11.68509500 -25.73751800 +v 5.7000000e-5 11.58329200 -26.95702700 +v 6.3000000e-5 12.78337700 -27.16254800 +v 1.00914000 11.68508500 -25.73751800 +v 0.98123300 10.04742100 -24.62956200 +v 4.1000000e-5 8.44826500 -27.39151000 +v -0.72026300 8.67406400 -27.75578500 +v 4.2000000e-5 8.48431300 -28.29700500 +v 0.72034900 8.67405700 -27.75578500 +v 3.7000000e-5 7.49872000 -27.38429100 +v 4.9000000e-5 10.03749900 -23.11098900 +v -0.92671300 8.53506900 -21.92589200 +v 5.3000000e-5 10.83585600 -24.16071100 +v -1.02001500 11.84424900 -24.74321700 +v 6.1000000e-5 12.35767500 -25.40923100 +v 6.3000000e-5 12.72184400 -25.35347900 +v 1.02013200 11.84423800 -24.74321700 +v 0.92679600 8.53506000 -21.92589200 +v 6.2000000e-5 12.60222800 -25.89424100 +v 6.1000000e-5 12.43225700 -24.52652900 +v 6.3000000e-5 12.78387200 -24.75336300 +v 6.4000000e-5 13.05511000 -25.09440200 +v 2.9000000e-5 6.66713900 -18.02463300 +v -0.76472200 4.97930100 -18.51949300 +v 3.9000000e-5 7.90586300 -19.59697900 +v 4.3000000e-5 8.84011200 -20.64203300 +v 0.76476400 4.97929400 -18.51949300 +v 1.0000000e-5 2.34261300 -17.77110700 +v 1.5000000e-5 3.58821400 -19.85622800 +v 0.78736600 4.87553800 -20.78534900 +v 1.8000000e-5 4.29836000 -21.03475600 +v 2.6000000e-5 6.06990400 -22.48316400 +v -0.78732400 4.87554500 -20.78534900 +v 2.4000000e-5 5.62700200 -20.94471200 +v 3.9000000e-5 7.98520700 -22.70804200 +v 4.6000000e-5 9.35529900 -25.04135100 +v -1.0000000e-6 -6.44448400 7.27236100 +v -1.0000000e-6 -8.30194600 4.10554500 +v -1.0000000e-6 -8.72783900 7.62699100 +v -1.0000000e-6 -7.33011700 2.17135600 +v 3.7200000e-4 4.00516300 17.23538600 +v -0.61151900 2.73085500 15.61799800 +v 8.6000000e-5 6.04123700 17.69214100 +v 2.0200000e-4 4.88150500 16.60086800 +v 0.61255700 2.27218400 15.92106400 +v 0.63873200 3.77532400 9.38166100 +v 0.60364400 1.66233100 10.90714500 +v -2.3000000e-5 4.42250800 10.89713900 +v 1.2400000e-4 4.64851400 14.61474100 +v -0.60337600 2.16205200 10.64126500 +v -0.63874700 3.77452500 9.35325100 +v -4.4000000e-5 5.10493100 9.13764900 +v -4.6000000e-5 5.46997100 9.93674700 +v -7.7000000e-5 5.34226800 11.12146400 +v 0.55094900 -1.59800900 7.19402800 +v 3.7400000e-4 -1.53811700 11.59978600 +v 9.7400000e-4 -0.79131600 14.90067300 +v 9.3200000e-4 0.20433200 16.83956300 +v -0.56389500 0.62579200 17.22780600 +v 1.0230000e-3 -0.22987200 17.25498000 +v -0.39616700 -0.22350600 17.54299900 +v 1.0550000e-3 -0.52465600 17.02950900 +v 1.1900000e-3 -1.54011400 16.66384100 +v 0.39824300 -0.22329200 17.54637700 +v 0.56567500 0.62614700 17.23444700 +v 1.0150000e-3 7.8151000e-2 17.94400000 +v 8.8900000e-4 0.91112500 17.98048400 +v -0.60373000 2.68434400 16.95183200 +v 2.8500000e-4 5.72530500 20.31161900 +v 0.60486500 2.78015300 17.50210200 +v 7.9900000e-4 2.51388100 20.69476900 +v 6.5600000e-4 4.16584200 22.62485100 +v 1.0920000e-3 -0.43613000 17.90929400 +v 1.1230000e-3 -0.75222000 17.59811000 +v -0.55095100 -1.59841500 7.17893900 +v -1.0000000e-6 -2.00304600 7.34242800 +v -0.71139400 -0.51856000 -9.64763600 +v -1.06322800 -1.53712500 -10.18832500 +v -0.90663700 -1.28153600 -10.71115100 +v -1.14429500 -2.44428800 -10.67093200 +v -0.92529000 -1.63513700 -10.24246500 +v -0.58833400 -3.20437200 -8.62448000 +v -1.33000600 -3.38778800 -10.71475100 +v -1.55034200 -4.31989100 -11.18308800 +v -1.32935700 -5.15210200 -9.69476600 +v -1.65609600 -4.89957800 -10.87464500 +v -1.75628000 -5.45400400 -11.15061700 +v -1.98731900 -6.91384900 -10.59548500 +v -1.86026300 -5.04663200 -9.65912900 +v -1.71532200 -2.98279400 -8.54893200 +v -2.09640300 -8.02020000 -9.13767100 +v -1.04689200 -6.28855700 -7.26440100 +v -0.56852800 -4.08297500 -6.40831000 +v -0.25516200 -1.75370300 -7.29674300 +v -0.16971400 -2.17245200 -5.56518700 +v -0.27187400 1.04811400 -7.20542000 +v -0.51380100 0.24887100 -5.64218300 +v -1.32950000 -1.94633600 -5.48752100 +v -1.33305200 -1.54346900 -7.22455800 +v -1.76788200 -3.84756400 -6.32792800 +v -2.22072300 -6.05593700 -7.18563100 +v -0.60984400 -0.35263800 -8.69297700 +v -0.67062000 1.03806400 -8.61586700 +v -0.66212500 -0.52115900 -5.03096200 +v -0.54912900 -0.23347600 -4.41617400 +v -0.59690600 -1.01983800 -3.68196100 +v -1.95157700 -7.25257700 -1.54450400 +v -2.23293000 -7.26498800 -4.88665600 +v -1.71162500 -5.63010600 -2.18099100 +v -1.76072500 -4.75336700 -4.21785800 +v -0.60190200 -1.87540300 -4.06505900 +v -0.63688800 -4.97374400 -4.29317500 +v -1.18321900 -7.47279400 -4.95708700 +v -0.74537200 -5.82036600 -2.24567700 +v -1.02599900 -7.43661000 -1.60642400 +v -0.50984500 -5.26038100 -0.47866900 +v -0.68069600 -2.99103500 -1.78644100 +v -0.77648700 -3.12785500 -2.79641200 +v -0.62738400 -2.17553000 -2.84964600 +v -2.12072200 -9.77928400 -4.39467200 +v -2.10037700 -9.94267900 -3.45606400 +v -2.08334000 -9.97200200 -2.43254700 +v -1.93335600 -9.81423700 -1.31619700 +v -1.64864300 -8.97627800 -0.70709200 +v -1.33503200 -7.38475600 0.67259100 +v -1.10391000 -6.16538300 1.13776900 +v -1.02231700 -5.65891500 0.81149800 +v -0.96301100 -5.05784600 1.06965300 +v -0.73858500 -4.17532000 0.59306000 +v -0.66028500 -3.35463500 -0.43449300 +v -1.48978600 -5.06473600 -0.41338400 +v -2.25467900 -10.22193100 -5.23150000 +v -2.21060400 -9.66648300 -6.15972400 +v -2.06347700 -8.29238700 -7.83253400 +v -2.14237500 -8.91445000 -7.27305600 +v -2.11132500 -9.00148500 -6.52637900 +v 1.14429400 -2.44428900 -10.67093200 +v 0.90663600 -1.28153600 -10.71115100 +v 0.92528900 -1.63513700 -10.24246500 +v 0.71139400 -0.51856000 -9.64763600 +v 1.06322800 -1.53712500 -10.18832500 +v 1.71532200 -2.98279400 -8.54893200 +v 0.60984400 -0.35263800 -8.69297700 +v 1.33305200 -1.54346900 -7.22455800 +v 0.67062100 1.03806300 -8.61586700 +v 0.27187400 1.04811400 -7.20542000 +v 0.25516200 -1.75370300 -7.29674300 +v 0.58833400 -3.20437200 -8.62448000 +v 1.98731900 -6.91384900 -10.59548500 +v 2.09640300 -8.02020000 -9.13767100 +v 1.86026300 -5.04663200 -9.65912900 +v 2.22072300 -6.05593700 -7.18563100 +v 1.76788200 -3.84756400 -6.32792800 +v 1.32950000 -1.94633600 -5.48752100 +v 0.51380100 0.24887100 -5.64218300 +v 0.16971400 -2.17245200 -5.56518700 +v 0.56852800 -4.08297500 -6.40831000 +v 1.04689200 -6.28855700 -7.26440100 +v 1.32935700 -5.15210200 -9.69476600 +v 1.02599900 -7.43661000 -1.60642400 +v 1.18321900 -7.47279400 -4.95708700 +v 0.74537200 -5.82036600 -2.24567700 +v 0.63688800 -4.97374400 -4.29317500 +v 0.60190200 -1.87540300 -4.06505900 +v 0.59690600 -1.01983800 -3.68196100 +v 1.76072500 -4.75336700 -4.21785800 +v 2.23293000 -7.26498800 -4.88665600 +v 1.71162500 -5.63010600 -2.18099100 +v 1.95157700 -7.25257700 -1.54450400 +v 1.48978600 -5.06473600 -0.41338400 +v 0.68069600 -2.99103500 -1.78644100 +v 0.77648700 -3.12785500 -2.79641200 +v 0.62738400 -2.17553000 -2.84964600 +v 0.50984500 -5.26038100 -0.47866900 +v 0.66028500 -3.35463500 -0.43449300 +v 0.73858500 -4.17532000 0.59306000 +v 0.96301100 -5.05784600 1.06965300 +v 1.02231700 -5.65891500 0.81149800 +v 1.10391000 -6.16538300 1.13776900 +v 1.33503200 -7.38475600 0.67259100 +v 1.64864300 -8.97627800 -0.70709200 +v 1.93335600 -9.81423700 -1.31619700 +v 2.08334000 -9.97200200 -2.43254700 +v 2.10037700 -9.94267900 -3.45606400 +v 2.12072200 -9.77928400 -4.39467200 +v 2.25467900 -10.22193100 -5.23150000 +v 2.21060400 -9.66648300 -6.15972400 +v 2.06347700 -8.29238700 -7.83253400 +v 2.14237500 -8.91445000 -7.27305600 +v 2.11132500 -9.00148500 -6.52637900 +v 0.66212500 -0.52115900 -5.03096200 +v 0.54912900 -0.23347600 -4.41617400 +v 1.33000400 -3.38778900 -10.71475100 +v 1.55033900 -4.31989200 -11.18308800 +v 1.65609300 -4.89957900 -10.87464500 +v 1.75627700 -5.45400500 -11.15061700 +v 2.05645200 4.71823100 7.66746700 +v 1.18999000 3.41512000 7.00838400 +v 2.17229800 5.99312600 7.42381700 +v 2.11387900 6.88608000 6.77542300 +v 2.08597300 3.37246700 6.76307900 +v 1.86389100 6.10163200 6.31428000 +v 1.59703900 4.85426600 6.01826600 +v 2.16592600 1.51686300 9.52253700 +v 2.44536600 2.64776700 9.96381500 +v 2.15159500 1.26336000 8.16088400 +v 2.37905600 3.25869700 9.22563600 +v 2.33502600 3.85072200 9.01623200 +v 2.21521700 3.69383200 7.80134800 +v 1.59088300 0.87385300 6.28116000 +v 1.37464600 3.46523300 4.65181600 +v 1.48825500 6.04563100 5.03901800 +v 0.70621700 3.51060900 4.83124400 +v 0.73630600 0.91953600 6.49777200 +v 1.35219500 1.24350700 8.36611600 +v 1.56764900 -1.92556800 9.06153300 +v 2.07000100 -0.86358900 10.14119400 +v 2.25512900 0.41598000 10.24789200 +v 1.10132900 -2.37413700 7.56198500 +v 0.89003100 -2.61801500 6.83668000 +v 0.84991100 1.51441300 5.00569700 +v 0.68505900 0.54410200 4.86180200 +v 0.72091900 -0.41144300 5.40904100 +v 0.66849900 2.17074200 4.05686600 +v 0.40155200 4.83254700 3.03857300 +v 0.60495200 -1.55462600 5.49379700 +v 0.62626100 -2.69335700 6.04987500 +v 0.95112100 4.79220200 2.88560600 +v 0.53567500 4.13615300 2.79837100 +v 0.58670400 5.47040700 2.48657500 +v 0.81519000 5.40092200 3.12562400 +v 1.02860900 5.16083600 3.86865300 +v 1.22363500 5.73393200 4.26795700 +v 1.71422200 3.67592700 7.93540800 +v -1.59703800 4.85301000 5.97163800 +v -1.18999000 3.41393600 6.96437300 +v -1.86389200 6.10032300 6.26569400 +v -2.11387900 6.88471400 6.72454100 +v -2.08597300 3.37055400 6.69206500 +v -2.17229800 5.99139800 7.35979100 +v -2.05645100 4.71629800 7.59571200 +v -2.16592600 1.51446200 9.43339300 +v -2.44536600 2.64502000 9.86184100 +v -1.35219600 1.24203000 8.31132300 +v -2.37905500 3.25606900 9.12820100 +v -2.33502600 3.84822600 8.92347000 +v -1.71422300 3.67411900 7.86830100 +v -0.73630700 0.91886900 6.47299700 +v -0.70621700 3.51009800 4.81230100 +v -1.48825500 6.04476300 5.00675900 +v -1.37464500 3.46430300 4.61717600 +v -1.59088400 0.87250800 6.23124100 +v -2.15159400 1.26116000 8.07929100 +v -1.56765000 -1.92675900 9.01730300 +v -2.07000200 -0.86541500 10.07334900 +v -2.25513000 0.41369900 10.16312000 +v -1.10132900 -2.37485400 7.53538700 +v -0.89003200 -2.61852700 6.81768900 +v -0.84991100 1.51378800 4.98247100 +v -0.68506000 0.54363900 4.84459800 +v -0.72092000 -0.41193100 5.39087700 +v -0.66850000 2.17032900 4.04152200 +v -0.95112100 4.79183300 2.87176900 +v -0.60495200 -1.55497800 5.48069700 +v -0.62626100 -2.69367600 6.03809700 +v -0.40155200 4.83237500 3.03230000 +v -0.53567400 4.13593100 2.79019400 +v -0.58670300 5.47022700 2.47991400 +v -0.81519000 5.40059900 3.11359900 +v -1.02860900 5.16031000 3.84917200 +v -1.22363400 5.73329500 4.24429000 +v -2.21521600 3.69160700 7.71881500 +v -1.32399600 10.10759400 -21.70157100 +v -1.07690500 8.95875500 -21.00243000 +v -0.75716400 8.78979300 -21.80523700 +v -0.76624100 8.58498600 -20.47533600 +v -1.24842700 11.00806300 -20.11475000 +v -1.23145900 10.10783200 -21.69575300 +v -1.00590000 9.67566300 -19.98662200 +v -0.98436900 8.95899400 -20.99661400 +v -0.87015500 9.12770800 -20.45442400 +v -1.41146600 12.11415100 -21.43366800 +v -1.45571600 12.37549500 -22.04214500 +v -1.42912400 10.85290800 -23.32258600 +v -1.38906700 12.17022300 -22.79202300 +v -1.40419200 12.44635600 -23.59315700 +v -1.43661200 11.23611200 -24.87534300 +v -1.34872300 12.34751500 -24.55221200 +v -1.21331000 11.88715600 -25.48330700 +v -0.81861000 9.36117900 -23.11468300 +v -1.33658900 10.85314400 -23.31676900 +v -0.91118300 9.98964700 -23.85982500 +v -0.92798200 10.24880200 -24.75848600 +v -1.34407600 11.23634700 -24.86953000 +v -1.00165400 10.80641400 -25.65524900 +v -1.10199000 11.37477900 -25.86927800 +v 1.23156900 10.10782000 -21.69575300 +v 0.98446800 8.95898400 -20.99661400 +v 0.75726100 8.78978500 -21.80523700 +v 0.76633600 8.58497800 -20.47533600 +v 1.41159700 12.11413800 -21.43366800 +v 1.24854500 11.00805100 -20.11475000 +v 1.00600500 9.67565200 -19.98662200 +v 0.87025500 9.12769900 -20.45442400 +v 1.07700300 8.95874500 -21.00243000 +v 1.32410600 10.10758100 -21.70157100 +v 1.45584900 12.37548100 -22.04214500 +v 1.42924200 10.85289400 -23.32258600 +v 1.38919800 12.17020800 -22.79202300 +v 1.40432600 12.44634200 -23.59315700 +v 1.43673500 11.23609600 -24.87534300 +v 1.34885600 12.34750200 -24.55221200 +v 0.81871300 9.36117200 -23.11468300 +v 0.91129200 9.98963700 -23.85982500 +v 0.92809400 10.24879400 -24.75848600 +v 1.00177300 10.80640300 -25.65524900 +v 1.10211400 11.37476800 -25.86927800 +v 1.34419800 11.23633400 -24.86953000 +v 1.33670700 10.85313000 -23.31676900 +v 1.21343900 11.88714400 -25.48330700 +v 1.38142500 0.69549400 4.18133100 +v 1.38773200 -0.31308000 4.66744100 +v 1.55878500 1.70145300 4.56661900 +v 1.57401500 -0.72489000 5.73958800 +v 1.81591900 2.13115300 5.60170900 +v 1.83115300 -0.29640600 6.77323500 +v 2.00220600 1.73279200 6.68015000 +v 2.00851100 0.72478600 7.16488900 +v 0.80365100 -0.66204900 5.89626000 +v 0.61736600 -0.24315800 4.82420300 +v 0.61106200 0.76695000 4.33789200 +v 0.78842100 1.77375400 4.72297700 +v 1.04555900 2.19942500 5.75789700 +v 1.23183500 1.79454600 6.83630600 +v 1.23814400 0.78010700 7.32110300 +v 1.06078200 -0.24017200 6.92961500 +v 1.71753200 -2.78350600 -5.49958200 +v 1.97282000 -3.79254400 -5.16007600 +v 1.37136000 -1.94873100 -4.98598900 +v 1.98767700 -4.32465400 -4.16368500 +v 1.13708900 -1.76396300 -3.91955000 +v 1.75341200 -4.06731800 -3.09404100 +v 1.15195500 -2.26433200 -2.92175500 +v 1.40723900 -3.18326100 -2.57826700 +v 1.24120100 -4.55968600 -4.28340900 +v 1.22633700 -4.02748500 -5.27980000 +v 0.97105700 -3.01768400 -5.61927300 +v 0.62488100 -2.17716300 -5.10542400 +v 0.70889600 -1.85895800 -4.03948400 +v 0.72375100 -2.34644500 -3.04112300 +v 0.66075800 -3.41200000 -2.69772000 +v 1.00692800 -4.30177200 -3.21375400 +v -2.00851200 0.72296200 7.09720100 +v -1.83115400 -0.29786900 6.71902100 +v -2.00220600 1.73097500 6.61268500 +v -1.81591900 2.12971500 5.54817300 +v -1.57401500 -0.72593400 5.70082000 +v -1.55878500 1.70043000 4.52861000 +v -1.38773100 -0.31388000 4.63773400 +v -1.38142500 0.69470300 4.15193600 +v -0.80365100 -0.66262000 5.87503700 +v -1.06078300 -0.24107800 6.89605900 +v -1.23814400 0.77890600 7.27648300 +v -1.23183500 1.79335000 6.79188300 +v -1.04555900 2.19853400 5.72490700 +v -0.78842100 1.77319700 4.70233600 +v -0.61106200 0.76657000 4.32387600 +v -0.61736600 -0.24354100 4.80996700 +v -1.40723700 -3.18308000 -2.57826100 +v -1.75340900 -4.06731900 -3.09404700 +v -1.15195200 -2.45444800 -2.68524900 +v -1.13708700 -1.76241400 -3.91948100 +v -1.98767400 -4.32465300 -4.16368400 +v -1.37135800 -1.94753300 -4.98593100 +v -1.97281700 -3.79254400 -5.16007600 +v -1.71752900 -2.78350700 -5.49958200 +v -1.24119800 -4.55968600 -4.28341100 +v -1.00692500 -4.30177000 -3.21374800 +v -0.66075600 -3.41200100 -2.69772100 +v -0.72374900 -2.38922000 -2.72681900 +v -0.70889300 -1.85797400 -4.03944000 +v -0.62487800 -2.17664100 -5.10539900 +v -0.97105400 -3.01768600 -5.61927300 +v -1.22633400 -4.02748500 -5.27980000 +v 3.3335000e-2 12.46595800 26.85734700 +v 2.6520000e-2 12.63921300 26.85111000 +v -3.0000000e-5 12.08854100 -4.0912000e-2 +v -3.0000000e-5 12.08854100 -4.0912000e-2 +v -8.0000000e-5 12.32410700 -4.7163000e-2 +v 7.1753000e-2 12.28526500 -24.51942300 +v -3.0000000e-5 12.08854100 -4.0912000e-2 +v 7.1753000e-2 12.28526500 -24.51942300 +v 7.8525000e-2 12.11200000 -24.51332700 +vt 7.7000000e-3 0.83611000 +vt 7.7060000e-3 0.83610700 +vt 1.0346000e-2 0.48475600 +vt 1.0371000e-2 0.48479600 +vt 1.5481000e-2 0.88562500 +vt 1.6103000e-2 0.88519300 +vt 2.0223000e-2 0.75737300 +vt 2.1729000e-2 0.75772700 +vt 2.4008000e-2 0.71836000 +vt 2.7252000e-2 5.7935000e-2 +vt 2.7390000e-2 4.0913000e-2 +vt 2.9826000e-2 0.42278000 +vt 2.9970000e-2 0.42236600 +vt 3.1423000e-2 2.6720000e-2 +vt 3.3595000e-2 0.11163200 +vt 3.3721000e-2 0.89704300 +vt 3.4255000e-2 0.89637300 +vt 3.6091000e-2 0.92139200 +vt 3.8029000e-2 0.92045200 +vt 3.9942000e-2 0.29127400 +vt 4.3607000e-2 0.55599200 +vt 4.3780000e-2 0.55651200 +vt 4.4368000e-2 2.4441000e-2 +vt 4.4550000e-2 5.6014000e-2 +vt 4.6503000e-2 4.0304000e-2 +vt 4.8043000e-2 0.15482700 +vt 5.1939000e-2 0.31836700 +vt 5.5321000e-2 0.69340600 +vt 5.5674000e-2 0.69397400 +vt 5.9105000e-2 0.12461100 +vt 5.9237000e-2 0.40515300 +vt 6.2206000e-2 5.1484000e-2 +vt 6.2919000e-2 0.57820400 +vt 6.3063000e-2 0.57833700 +vt 6.6584000e-2 0.23476300 +vt 6.7450000e-2 0.94223100 +vt 6.7624000e-2 0.94212100 +vt 7.0440000e-2 3.4963000e-2 +vt 7.0997000e-2 0.18716800 +vt 7.3031000e-2 0.38203800 +vt 7.7809000e-2 0.11616300 +vt 7.7868000e-2 0.79595600 +vt 7.8415000e-2 0.35248700 +vt 8.2668000e-2 0.17125100 +vt 8.2745000e-2 0.88842700 +vt 8.3389000e-2 0.29115600 +vt 8.5357000e-2 0.41096500 +vt 8.7455000e-2 0.67694400 +vt 8.7506000e-2 0.67706400 +vt 9.2184000e-2 0.47346200 +vt 9.2857000e-2 0.32244100 +vt 9.5749000e-2 0.15734300 +vt 9.7106000e-2 0.58248900 +vt 9.7332000e-2 0.58260300 +vt 0.10283200 0.17985900 +vt 0.10905100 0.23264800 +vt 0.11155200 0.37424500 +vt 0.11330500 0.95084100 +vt 0.11920600 0.66588000 +vt 0.11933700 0.14912200 +vt 0.12387100 0.41423800 +vt 0.12397600 0.29948900 +vt 0.12407400 0.60877600 +vt 0.12465100 0.61062300 +vt 0.12637000 0.83825000 +vt 0.13174500 0.17664100 +vt 0.13725100 0.63723300 +vt 0.14228000 0.35678900 +vt 0.14414900 0.53466900 +vt 0.15006100 0.21075300 +vt 0.15745100 9.8830000e-2 +vt 0.16144200 0.26530800 +vt 0.16145700 0.44388600 +vt 0.16225500 0.93934000 +vt 0.16466600 0.62217800 +vt 0.16473600 0.62204100 +vt 0.16742400 0.46179100 +vt 0.17328400 0.32207200 +vt 0.17441600 6.4364000e-2 +vt 0.17576600 0.63873600 +vt 0.17678000 0.13615300 +vt 0.17999900 0.73681000 +vt 0.18105200 0.13586100 +vt 0.18677300 0.50299400 +vt 0.18853800 8.8750000e-2 +vt 0.19126400 0.91635000 +vt 0.19894500 0.57971800 +vt 0.19917500 0.65326800 +vt 0.20122100 0.31421600 +vt 0.20128300 0.12224800 +vt 0.20488100 0.83063600 +vt 0.20937600 0.15203400 +vt 0.21126300 0.24307700 +vt 0.21230300 0.61920600 +vt 0.21526200 9.9750000e-2 +vt 0.21857900 0.53191900 +vt 0.22049500 0.93961100 +vt 0.22162200 0.49143400 +vt 0.22188700 0.10502400 +vt 0.22228900 3.8479000e-2 +vt 0.22364300 0.13604000 +vt 0.22364300 0.64308000 +vt 0.23496400 0.15627600 +vt 0.23578300 0.13561900 +vt 0.23773200 0.10617000 +vt 0.23842200 0.44459900 +vt 0.23879100 0.60371500 +vt 0.24248500 0.57440900 +vt 0.24442300 0.37162000 +vt 0.24839600 0.14158000 +vt 0.25219000 0.65290700 +vt 0.25250100 0.12008700 +vt 0.25367500 0.41191600 +vt 0.25373600 7.5406000e-2 +vt 0.25608900 0.93817400 +vt 0.26443300 0.97798600 +vt 0.26569800 5.8372000e-2 +vt 0.26866600 0.19987500 +vt 0.27182600 0.73505200 +vt 0.27317500 0.53888200 +vt 0.28624300 0.82214400 +vt 0.29313400 2.5426000e-2 +vt 0.29736600 0.63925800 +vt 0.29805800 0.90057000 +vt 0.30301200 0.99335800 +vt 0.31556100 0.38166100 +vt 0.31595400 0.97001800 +vt 0.33096100 0.53324900 +vt 0.33949800 0.61196200 +vt 0.33980400 0.20991700 +vt 0.34944100 0.98287800 +vt 0.35485000 6.8903000e-2 +vt 0.35649700 0.40479900 +vt 0.35728600 0.88070000 +vt 0.36186400 0.64875300 +vt 0.36501500 0.43053700 +vt 0.36667200 0.72405600 +vt 0.36980100 0.80934100 +vt 0.37001900 4.0801000e-2 +vt 0.37200300 2.8906000e-2 +vt 0.37296400 0.33845900 +vt 0.37668300 0.13926400 +vt 0.37739000 0.46155400 +vt 0.38198300 0.65124100 +vt 0.38300600 0.26732000 +vt 0.38525100 1.7476000e-2 +vt 0.39087200 0.52364600 +vt 0.39706400 0.46461500 +vt 0.39821000 0.43042100 +vt 0.39864200 5.6393000e-2 +vt 0.40117000 0.39845200 +vt 0.40224700 0.49902200 +vt 0.40440000 3.2643000e-2 +vt 0.40532600 0.68524100 +vt 0.40718700 0.70771800 +vt 0.40739300 0.70758800 +vt 0.40771100 0.54611000 +vt 0.40801200 0.18847600 +vt 0.40854100 0.97298900 +vt 0.42260400 0.50703000 +vt 0.42412300 0.62230700 +vt 0.42707100 0.89662800 +vt 0.42725500 0.72079700 +vt 0.42743400 0.89707300 +vt 0.42750500 0.54161300 +vt 0.42919700 0.14149000 +vt 0.43053800 0.68047100 +vt 0.43057800 0.46009100 +vt 0.43059400 0.75953100 +vt 0.43086700 0.75946800 +vt 0.43829600 0.41450800 +vt 0.43875600 0.41394400 +vt 0.43975500 0.43873500 +vt 0.44032300 0.40609300 +vt 0.44128500 7.2445000e-2 +vt 0.44477900 0.52194300 +vt 0.44673100 0.79063400 +vt 0.44800700 0.57842400 +vt 0.44898200 0.82510400 +vt 0.44910200 0.82551800 +vt 0.44935900 0.82930900 +vt 0.44938600 0.82970600 +vt 0.44965200 0.94390800 +vt 0.44969200 0.42333300 +vt 0.44999300 0.56250100 +vt 0.45210500 0.87292000 +vt 0.45233900 0.87315500 +vt 0.45553000 0.47640100 +vt 0.45625900 0.40937900 +vt 0.46062200 0.42427700 +vt 0.46266800 0.97686400 +vt 0.46273300 0.97413000 +vt 0.46545500 0.54543100 +vt 0.46930100 0.82834100 +vt 0.46950300 0.82786500 +vt 0.46958300 0.57788300 +vt 0.47070600 0.46497500 +vt 0.47113800 0.28763600 +vt 0.47683000 0.69918500 +vt 0.47707800 0.51180400 +vt 0.47823500 0.55866900 +vt 0.47912300 0.53283400 +vt 0.48043800 0.13392200 +vt 0.48773500 0.62838000 +vt 0.49126600 0.57676100 +vt 0.49139400 0.45145600 +vt 0.49561400 0.37234600 +vt 0.49708200 0.50537000 +vt 0.49830700 0.54140900 +vt 0.50461500 0.67646200 +vt 0.50791600 0.56398300 +vt 0.50956300 0.38443100 +vt 0.51223000 0.48647600 +vt 0.51293200 0.71315600 +vt 0.51383000 0.64671100 +vt 0.51685300 0.91538500 +vt 0.51685900 0.94367500 +vt 0.51810300 0.54178000 +vt 0.51843300 0.34285200 +vt 0.51970100 0.50883800 +vt 0.51986000 0.25047900 +vt 0.53260900 0.44097200 +vt 0.53272500 0.51895500 +vt 0.54186000 0.18508000 +vt 0.54482700 0.75139300 +vt 0.54646600 8.9004000e-2 +vt 0.55208900 0.12960900 +vt 0.55494500 0.91537200 +vt 0.55495700 0.94366400 +vt 0.55625900 0.54811100 +vt 0.56065800 0.67114800 +vt 0.57048500 0.50296600 +vt 0.57591300 0.68398300 +vt 0.57747500 8.3758000e-2 +vt 0.57754900 0.69383900 +vt 0.58193400 0.32926400 +vt 0.58299400 0.15709300 +vt 0.58506100 0.56264300 +vt 0.59153500 0.67858000 +vt 0.59303700 0.91535000 +vt 0.59305400 0.94364100 +vt 0.59426300 0.23457000 +vt 0.59527000 0.65444000 +vt 0.59693000 0.37235600 +vt 0.59961700 0.70277500 +vt 0.60008200 0.79332300 +vt 0.60051000 0.66380800 +vt 0.60325500 0.66170600 +vt 0.60383900 0.64374400 +vt 0.60933700 0.67578200 +vt 0.60959100 3.9395000e-2 +vt 0.60994300 3.9704000e-2 +vt 0.61476300 0.65637600 +vt 0.61637200 0.64429100 +vt 0.61827900 0.17145300 +vt 0.62044000 0.68413500 +vt 0.62643400 0.66168800 +vt 0.62869000 0.74992100 +vt 0.63112900 0.91532100 +vt 0.63115000 0.94361000 +vt 0.63506400 0.52988200 +vt 0.63735700 0.81457700 +vt 0.63818400 0.29850000 +vt 0.64215600 0.19820400 +vt 0.64891400 0.31761800 +vt 0.65332500 0.79812900 +vt 0.65874000 0.97982200 +vt 0.65880400 0.97708700 +vt 0.66172700 1.3981000e-2 +vt 0.66175700 1.4034000e-2 +vt 0.66419600 0.47146200 +vt 0.66595000 0.28299200 +vt 0.66764500 0.72585500 +vt 0.66922200 0.91528700 +vt 0.66924500 0.94357600 +vt 0.67038000 0.32766400 +vt 0.67333000 0.15067600 +vt 0.67467700 0.20658600 +vt 0.67768800 0.30092500 +vt 0.67920300 0.79689500 +vt 0.68614000 0.24451200 +vt 0.68678300 0.31401100 +vt 0.68772600 0.28456800 +vt 0.69769500 0.28928400 +vt 0.70122500 0.31214600 +vt 0.70379500 0.82729000 +vt 0.70490800 0.69723000 +vt 0.70626300 9.1941000e-2 +vt 0.70643800 2.0887000e-2 +vt 0.70731600 0.91525300 +vt 0.70733800 0.94354200 +vt 0.70856100 0.30316900 +vt 0.71022200 0.36545900 +vt 0.72311600 0.74426700 +vt 0.73292300 5.1895000e-2 +vt 0.74023400 0.30435400 +vt 0.74099500 0.41529200 +vt 0.74246000 0.22958100 +vt 0.74541200 0.91522300 +vt 0.74543000 0.94351300 +vt 0.76274800 0.58728800 +vt 0.76402800 0.15546200 +vt 0.76658400 0.30227600 +vt 0.77789000 4.7887000e-2 +vt 0.77790600 4.7831000e-2 +vt 0.78171200 0.32665900 +vt 0.78350900 0.91519900 +vt 0.78352200 0.94349100 +vt 0.78623300 0.64424100 +vt 0.78691800 0.12464300 +vt 0.78998100 7.6590000e-2 +vt 0.79045200 0.30262000 +vt 0.79069800 0.30273300 +vt 0.79076700 7.6062000e-2 +vt 0.79412600 0.27358700 +vt 0.79780200 0.61517700 +vt 0.80867600 0.19886300 +vt 0.80982800 8.8776000e-2 +vt 0.81157900 0.59001600 +vt 0.81888700 0.26576600 +vt 0.82160700 0.91518800 +vt 0.82161300 0.94347900 +vt 0.82393500 0.13929800 +vt 0.82660400 0.85573800 +vt 0.83079500 0.79357200 +vt 0.83479800 0.52218200 +vt 0.83505500 0.82873000 +vt 0.83903900 0.24404200 +vt 0.84245800 0.11285200 +vt 0.85132400 0.50640600 +vt 0.85428300 8.1755000e-2 +vt 0.85782800 0.19693600 +vt 0.86081500 0.98295700 +vt 0.86087900 0.98022100 +vt 0.86268000 5.0210000e-2 +vt 0.86324900 0.55719600 +vt 0.86705700 0.15972200 +vt 0.87303700 0.56991800 +vt 0.87671000 5.6437000e-2 +vt 0.87781100 0.59256800 +vt 0.88397100 0.89381000 +vt 0.88455500 0.62381200 +vt 0.88499800 0.83166100 +vt 0.89163800 0.53645300 +vt 0.89175500 0.18801900 +vt 0.89341000 6.3850000e-2 +vt 0.89496200 0.16014900 +vt 0.89816200 0.98638600 +vt 0.90160200 0.87154400 +vt 0.90466200 0.93363100 +vt 0.90651900 0.96286600 +vt 0.91408900 0.84348000 +vt 0.91854300 0.22577300 +vt 0.92100600 0.96254500 +vt 0.92362900 0.51242400 +vt 0.92438400 0.14016200 +vt 0.92646800 0.92317300 +vt 0.92862200 0.29772900 +vt 0.92985600 0.43841900 +vt 0.93032500 0.97733400 +vt 0.93170100 0.37272600 +vt 0.94206000 0.52490800 +vt 0.94467500 0.85545600 +vt 0.94611200 0.90027300 +vt 0.94996800 0.21661700 +vt 0.95170700 0.91525900 +vt 0.95170800 0.94850000 +vt 0.95267300 0.87539100 +vt 0.95341500 0.43864000 +vt 0.95469000 0.12372900 +vt 0.95507600 0.83640400 +vt 0.95878400 0.37744100 +vt 0.96070200 0.29436700 +vt 0.96529200 0.83569300 +vt 0.96686200 0.90516300 +vt 0.96993000 0.54615800 +vt 0.97010500 0.85792100 +vt 0.97499000 0.84932900 +vt 0.97599900 0.83837700 +vt 0.97994500 0.86679700 +vt 0.98151000 0.38807800 +vt 0.98254400 0.21363800 +vt 0.98333400 0.44849800 +vt 0.98881800 0.30003300 +vt 0.99589000 0.89331200 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.95528439 0.13544713 -0.26284179 +vn -2.1810569e-4 0.91459815 -0.40436391 +vn -1.3901356e-4 0.32551868 -0.94553560 +vn -0.95537989 0.13505654 -0.26269565 +vn 0.97181128 6.7853360e-2 0.22578476 +vn 2.1241041e-4 -0.83022561 0.55742748 +vn 0.93638645 -0.34827136 -4.3445044e-2 +vn -1.0164327e-5 -0.30634038 -0.95192204 +vn -0.93625058 -0.34865430 -4.3301549e-2 +vn -0.97180463 6.7455949e-2 0.22593240 +vn -3.9931054e-5 -0.17131970 -0.98521549 +vn -0.99467224 -7.0781520e-2 -7.4947331e-2 +vn -1.9667573e-4 0.69072351 -0.72311894 +vn -0.95133978 0.23742245 -0.19642608 +vn 1.4930921e-2 0.67092478 -0.74137508 +vn -0.99610914 6.0261945e-2 -6.4304565e-2 +vn 2.5691575e-2 0.70381721 -0.70991639 +vn -0.99806429 5.8666707e-2 -2.0637284e-2 +vn 0.99468965 -7.0374844e-2 -7.5099167e-2 +vn 0.95432848 0.23228763 -0.18788189 +vn 0.99872980 3.3908943e-2 -3.7269009e-2 +vn 0.99907341 4.2188458e-2 -8.5116849e-3 +vn -1.7179473e-2 -0.68934958 0.72422512 +vn -1.1691829e-2 -0.66034665 0.75086990 +vn 1.1761013e-4 -0.21241833 0.97717882 +vn 1.9410158e-4 -0.67542171 0.73743167 +vn -3.9345113e-2 -6.9641222e-2 0.99679590 +vn -0.94681907 0.25457538 0.19678676 +vn 1.6876244e-4 -0.50192280 0.86491241 +vn 0.94673995 0.25482573 0.19684337 +vn 3.8460132e-6 0.32992812 0.94400606 +vn -2.1775233e-4 0.95688249 -0.29047524 +vn -1.2030139e-4 0.80821380 0.58888915 +vn -1.5599102e-4 0.91339719 0.40706946 +vn -0.97757764 1.5246379e-2 0.21002264 +vn -2.4245077e-7 0.80019889 0.59973472 +vn -0.98573470 0.16809497 8.4367921e-3 +vn 0.0000000e+0 0.99914795 4.1272006e-2 +vn 0.98574834 0.16801336 8.4685077e-3 +vn 0.97757758 1.5246588e-2 0.21002292 +vn -9.3517640e-5 -0.61249759 0.79047245 +vn 0.99173658 7.1724972e-2 0.10636767 +vn 0.98704600 -5.9286497e-2 0.14908152 +vn -7.1668844e-7 0.82792400 -0.56084031 +vn 0.94771303 0.25856739 -0.18703722 +vn -3.5382248e-7 0.78172524 -0.62362300 +vn -7.9777363e-7 0.99702501 -7.7078704e-2 +vn -0.94771150 0.25857142 -0.18703940 +vn -0.98704599 -5.9286543e-2 0.14908158 +vn -0.99173658 7.1724998e-2 0.10636770 +vn -1.2638985e-7 0.13748223 0.99050423 +vn -1.3350696e-6 -0.74885405 0.66273495 +vn 0.99409746 0.10202971 3.6880680e-2 +vn -6.7915554e-4 0.96767174 0.25221211 +vn 0.98972858 -0.14205913 -1.6016688e-2 +vn 0.99819785 4.1576457e-2 4.3271910e-2 +vn 0.95380483 -0.12181357 -0.27462300 +vn 0.93477707 -0.33957789 0.10430097 +vn 0.99165909 -8.5672916e-2 -9.6293277e-2 +vn -0.99413457 0.10167887 3.6849235e-2 +vn -0.98953430 -0.14328046 -1.7105131e-2 +vn -0.99822425 4.0869055e-2 4.3336686e-2 +vn -0.95320787 -0.12241400 -0.27642282 +vn -0.93513147 -0.33904530 0.10284660 +vn -0.99160723 -8.5391430e-2 -9.7074264e-2 +vn -4.0429384e-3 -0.72369998 0.69010289 +vn 2.1125250e-4 -0.99885960 4.7743603e-2 +vn 4.3164857e-4 0.77651620 -0.63009714 +vn 1.5453092e-3 1.0757847e-2 -0.99994094 +vn 1.5189892e-3 -0.77580043 -0.63097654 +vn 1.2652807e-4 -0.99791923 -6.4476374e-2 +vn 0.99322599 -7.4031033e-2 8.9563041e-2 +vn 0.99454434 0.10139541 2.4505510e-2 +vn 3.6206191e-7 0.99610665 8.8156404e-2 +vn -1.4297770e-7 0.97059730 0.24070913 +vn -0.99454432 0.10139625 2.4502816e-2 +vn -0.99322615 -7.4029648e-2 8.9562420e-2 +vn 5.7301740e-7 0.93869009 -0.34476211 +vn -0.93999550 0.33020289 -8.5875012e-2 +vn 5.0657758e-7 0.54458926 -0.83870289 +vn -2.3845251e-7 -0.32815889 -0.94462254 +vn -0.97915444 -0.19256083 6.4628979e-2 +vn -7.8184440e-7 -0.90809291 -0.41876876 +vn -7.4060190e-7 -0.89380931 0.44844723 +vn 0.97915404 -0.19256284 6.4629120e-2 +vn 0.93999597 0.33020159 -8.5874832e-2 +vn -2.9033837e-7 -0.99929447 -3.7557487e-2 +vn -6.5903505e-7 -0.66236514 0.74918117 +vn 5.1415154e-7 0.77959451 0.62628460 +vn 5.5889871e-7 0.62646354 0.77945073 +vn -5.6249153e-9 -0.90900627 -0.41678244 +vn -0.96616469 -0.15721208 -0.20447533 +vn 0.96616472 -0.15721273 -0.20447465 +vn -2.6411608e-7 0.95012528 -0.31186848 +vn 0.99864312 -5.0869149e-2 -1.1146466e-2 +vn 0.98493359 -0.13898351 -0.10290485 +vn 0.98620014 7.1401375e-2 0.14936908 +vn -3.6475656e-7 0.12592396 -0.99203990 +vn 0.99923038 2.8401965e-2 2.7055003e-2 +vn 3.2712653e-17 -0.40971037 -0.91221566 +vn -6.8120774e-8 -0.54394763 -0.83911916 +vn -0.99923038 2.8401811e-2 2.7055140e-2 +vn -0.98620013 7.1401260e-2 0.14936919 +vn -0.98493364 -0.13898332 -0.10290467 +vn -0.99075437 -0.11641267 -6.9669663e-2 +vn 0.99219630 0.11076771 5.7245153e-2 +vn -3.6659662e-7 0.98453240 0.17520262 +vn 3.1038707e-2 0.99893675 -3.4087713e-2 +vn -0.99220026 0.11073575 5.7238401e-2 +vn -0.99864313 -5.0869046e-2 -1.1146268e-2 +vn -1.2809813e-7 0.39365950 0.91925633 +vn -1.7108065e-7 4.9545360e-3 0.99998773 +vn -0.89457713 0.21611218 0.39118702 +vn 0.89457702 0.21611218 0.39118726 +vn -3.1013503e-7 0.96258145 -0.27099252 +vn -5.3287867e-7 0.10766059 0.99418771 +vn -2.2716000e-7 -0.53343057 0.84584385 +vn -3.5939968e-6 -0.73046851 0.68294638 +vn 0.86987773 0.10933999 -0.48099637 +vn 3.0073978e-8 -6.1025723e-5 1.00000000 +vn 0.82235625 0.14893962 0.54913312 +vn 5.6866367e-7 0.12824971 -0.99174191 +vn -0.86987672 0.10934772 -0.48099643 +vn 4.4880463e-7 0.17883077 -0.98387985 +vn -0.82235496 0.14894672 0.54913313 +vn -0.99408889 6.1588096e-2 -8.9410200e-2 +vn 2.1206410e-6 0.45035823 0.89284795 +vn 1.2039601e-6 0.29627832 0.95510165 +vn -0.95122752 8.1855057e-2 0.29743226 +vn -4.8652640e-6 -0.96887137 0.24756468 +vn 7.3491749e-7 0.14193583 0.98987586 +vn 0.95122813 8.1846892e-2 0.29743256 +vn 1.5021929e-6 0.30084911 -0.95367175 +vn 0.99408946 6.1579148e-2 -8.9410029e-2 +vn 4.6684861e-6 0.99704783 -7.6782927e-2 +vn 4.3079150e-6 0.97979927 -0.19998346 +vn 0.99940671 3.3580865e-2 -7.6524979e-3 +vn -3.0125247e-6 -0.76121254 -0.64850248 +vn -2.9675974e-6 -0.71606824 -0.69803029 +vn -0.99940649 3.3587289e-2 -7.6532010e-3 +vn 3.4093670e-6 0.65624676 -0.75454635 +vn 4.8140745e-6 0.96397158 0.26600527 +vn 1.1889028e-6 -0.96341406 -0.26801746 +vn 0.99075434 -0.11641282 -6.9669932e-2 +vn -5.7908024e-7 -0.91710369 -0.39864874 +vn -2.2821490e-6 -0.75721778 -0.65316249 +vn 3.1729748e-6 0.94009667 0.34090799 +vn 1.0576679e-6 0.12637632 -0.99198237 +vn -0.97681046 0.16898476 -0.13147422 +vn 7.6489800e-8 0.90238014 0.43094092 +vn 0.0000000e+0 0.88749369 0.46081987 +vn 0.97681054 0.16898450 -0.13147399 +vn 0.0000000e+0 -0.94134543 -0.33744448 +vn 0.0000000e+0 -0.24842891 -0.96865013 +vn -9.7106171e-17 0.82734111 -0.56169981 +vn 0.97362729 -0.22813300 2.2887555e-3 +vn 1.0805004e-4 -0.92941481 0.36903672 +vn 0.98612746 -0.16368723 -2.7552200e-2 +vn -1.7654961e-7 -0.88241778 -0.47046665 +vn -6.1034010e-17 -0.93981097 -0.34169481 +vn -9.2975754e-17 -0.90373321 -0.42809611 +vn -0.98612750 -0.16368702 -2.7552075e-2 +vn -0.97783732 -0.20935622 -2.0359391e-3 +vn 0.98727370 9.6276130e-2 0.12657626 +vn -7.4964446e-3 -0.99506866 -9.8904792e-2 +vn 0.98904157 -0.13439132 6.1120726e-2 +vn -7.2428773e-4 -0.95697742 0.29016150 +vn 0.99009821 3.7565160e-4 0.14037589 +vn -1.6168994e-3 -0.65250288 0.75778452 +vn -3.1313362e-3 -0.19475190 0.98084754 +vn -0.99040762 1.5308090e-3 0.13816803 +vn -0.98836454 -0.13679441 6.6504296e-2 +vn -0.98010855 0.18073289 8.1992971e-2 +vn -4.7113603e-2 0.83980736 0.54083630 +vn -0.16703952 0.14867584 0.97467599 +vn 4.0503950e-3 0.64329348 -0.76560897 +vn 8.3120547e-2 0.96893000 -0.23294984 +vn -0.98744472 7.2390206e-2 -0.14040154 +vn 8.1129709e-3 -0.34938675 -0.93694348 +vn 0.98863189 7.1901515e-2 -0.13204983 +vn -4.2626181e-3 0.32830364 0.94456262 +vn -0.95945308 0.27415723 -6.5479719e-2 +vn 6.6830731e-3 -0.17453866 -0.98462764 +vn 0.95949164 0.27505637 -6.0990073e-2 +vn -2.1195470e-3 0.93477681 0.35522926 +vn 1.3224702e-3 0.97263961 -0.23231538 +vn 1.5115458e-4 -0.90176381 -0.43222912 +vn 2.1319713e-4 -0.84081004 0.54133025 +vn 8.1829626e-5 -2.5813542e-2 0.99966677 +vn 1.3044177e-6 0.28560941 -0.95834611 +vn -0.99789466 6.0842749e-2 2.2458824e-2 +vn 4.7635134e-6 0.89367061 -0.44872357 +vn 2.1774290e-6 0.41151443 -0.91140325 +vn 0.99789529 6.0832283e-2 2.2459251e-2 +vn -5.2128106e-6 -0.94482071 0.32758790 +vn -0.94605249 -0.32391489 -7.9895345e-3 +vn -0.93380756 0.22801507 -0.27570377 +vn -2.8262860e-6 -0.50728605 -0.86177773 +vn 3.3874109e-6 0.77304272 -0.63435397 +vn 0.93380984 0.22800582 -0.27570371 +vn 0.94604919 -0.32392452 -7.9892759e-3 +vn -2.8668894e-6 -0.44531557 0.89537369 +vn -0.95357795 -0.26775121 -0.13783465 +vn -1.7278457e-6 -0.34207917 -0.93967114 +vn 0.95357530 -0.26776073 -0.13783443 +vn -5.1912207e-6 -0.87442503 0.48516065 +vn 4.1437059e-6 0.84737546 0.53099418 +vn -0.96073827 0.24015379 0.13895373 +vn 2.3411007e-6 0.50688195 0.86201548 +vn -0.82384253 0.49322436 0.27930846 +vn 4.6009267e-6 0.94536436 -0.32601568 +vn 2.0504763e-6 0.37884515 -0.92546008 +vn 0.82384730 0.49321615 0.27930888 +vn 0.96074075 0.24014374 0.13895393 +vn 4.5008292e-6 0.95236527 0.30495965 +vn 1.8516019e-6 0.38417148 0.92326176 +vn 3.4434334e-6 0.66526162 0.74661032 +vn 5.5269499e-6 0.99883373 -4.8282318e-2 +vn 2.9652010e-6 0.69199397 0.72190328 +vn -0.99432417 7.1062823e-2 7.9180292e-2 +vn 3.6132828e-6 0.72715314 0.68647528 +vn 4.0161165e-6 0.83580993 0.54901891 +vn 0.99432482 7.1053166e-2 7.9180763e-2 +vn -3.3622216e-6 -0.80580121 -0.59218613 +vn -4.2892070e-6 -0.93554919 -0.35319643 +vn 0.96983356 -6.9454266e-2 -0.23366423 +vn -3.6162247e-6 -0.75359926 -0.65733413 +vn 1.2115194e-6 0.44882873 -0.89361780 +vn -0.96983418 -6.9445627e-2 -0.23366420 +vn 1.8039502e-6 0.65114994 -0.75894911 +vn -3.8163447e-6 -0.80015208 -0.59979717 +vn -4.6158786e-6 -0.97660062 -0.21506101 +vn 1.2314475e-5 -0.99983811 1.7993047e-2 +vn -3.6371444e-7 -0.94741826 -0.31999787 +vn -1.0336581e-6 -0.22571524 0.97419332 +vn -4.0126819e-7 -0.84753581 -0.53073821 +vn -2.8121614e-2 0.99959234 -4.9323433e-3 +vn -0.99664362 8.1537174e-2 -7.2931415e-3 +vn 8.9690689e-2 0.93026723 0.35575056 +vn 9.3139943e-2 0.82862289 -0.55200458 +vn 0.99869917 4.6433199e-2 2.1069677e-2 +vn 0.97613674 0.20909136 5.8633296e-2 +vn 0.99739728 -2.2457299e-2 6.8515277e-2 +vn 1.2326068e-2 0.67306064 0.73948458 +vn 2.7574178e-2 0.99571317 -8.8288962e-2 +vn -0.99784435 -2.2859822e-3 6.5585260e-2 +vn -0.97591960 0.21079752 5.6083388e-2 +vn 1.2257083e-3 0.94676119 -0.32193438 +vn 7.9412067e-4 0.98119699 -0.19300733 +vn -3.5857574e-3 0.46380264 0.88593129 +vn 0.86068246 -0.49975124 -9.7336580e-2 +vn -4.3208037e-3 -0.97542095 0.22030729 +vn -1.8306155e-2 -0.95909718 0.28248447 +vn -1.3538471e-3 -0.77027865 -0.63770602 +vn -0.97920225 -0.20240742 -1.3935332e-2 +vn 3.0928342e-3 -0.17231393 -0.98503723 +vn -0.99182932 -0.12043694 4.2066039e-2 +vn 2.2309636e-3 0.49148721 -0.87088194 +vn 1.9648019e-3 -0.73956486 -0.67308243 +vn 0.99164059 -0.12079966 4.5347438e-2 +vn 0.97946817 -0.20142043 -8.4804911e-3 +vn -2.1636246e-3 1.1610650e-2 0.99993025 +vn -2.1331835e-3 -0.18161264 0.98336784 +vn -0.99986198 -1.0880190e-3 1.6578231e-2 +vn -1.5918346e-4 0.82966441 -0.55826243 +vn 0.99988131 -7.4299753e-3 1.3496594e-2 +vn -5.3768576e-3 -0.83680330 0.54747724 +vn 1.4065044e-4 -0.71867578 0.69534531 +vn -1.8677207e-3 -0.40342373 0.91501137 +vn -1.1825489e-3 -0.73320306 0.68000873 +vn -0.86231818 -0.49676790 -9.8127504e-2 +vn 2.0760947e-3 -0.98617315 -0.16570520 +vn 0.15530636 0.84457297 -0.51242212 +vn -0.94992734 0.27914038 -0.14042327 +vn 0.13719497 0.39382719 -0.90888816 +vn -1.6630828e-2 8.3437854e-2 -0.99637420 +vn 0.97456847 -0.12685809 -0.18472497 +vn 0.96848680 -0.11760074 -0.21955268 +vn 9.1270491e-4 0.26939061 -0.96303056 +vn -7.6531872e-2 -2.4991294e-2 -0.99675389 +vn 0.94135260 -0.23465272 -0.24247345 +vn -0.10786760 -3.4518474e-2 -0.99356583 +vn -5.9382842e-2 0.11356847 -0.99175394 +vn -0.15402749 -0.54563111 -0.82374888 +vn -0.98670450 0.12170573 -0.10771230 +vn -0.96309393 0.25197596 -9.4647743e-2 +vn -0.18617846 -0.81743537 -0.54510274 +vn 0.94609450 -0.28772828 -0.14871998 +vn 0.98431163 -0.17618005 9.5500325e-3 +vn 0.98709665 -4.1785377e-2 -0.15457743 +vn 0.99219789 1.5954338e-2 0.12364792 +vn 0.13126687 0.96807264 0.21355181 +vn 1.9866984e-2 0.74697511 0.66455511 +vn -0.95244055 0.23377198 0.19546782 +vn -0.96474393 0.26192018 -2.5825864e-2 +vn -0.97096541 0.19159250 0.14324278 +vn -0.99711333 7.2326136e-2 -2.3107033e-2 +vn 0.15426305 0.58227465 -0.79822249 +vn 0.19004391 0.52255671 -0.83115449 +vn -2.4742800e-2 0.98097420 0.19255497 +vn 1.6554586e-2 0.99948645 2.7436735e-2 +vn 0.10801656 2.8636689e-2 0.99373657 +vn -0.98458479 5.5942418e-2 0.16572036 +vn -0.99859905 4.0043736e-2 3.4589610e-2 +vn -0.95928338 0.27118783 7.8946517e-2 +vn -0.95339739 0.25662444 0.15867358 +vn 0.12513768 2.4167362e-2 0.99184500 +vn 0.99375470 -0.10629291 3.3961821e-2 +vn 0.94317941 -0.32063740 -8.7202405e-2 +vn 0.99401068 -9.6355579e-2 -5.1559436e-2 +vn 0.95161577 -0.30718290 8.1293032e-3 +vn 0.98536176 -9.0571823e-2 0.14442627 +vn 0.18281587 0.98238161 -3.8790888e-2 +vn 0.18692559 0.65404939 0.73299265 +vn 0.16166379 0.43847253 0.88408521 +vn -0.16852767 -0.97232355 0.16181884 +vn -0.19300782 -0.98065558 -3.2597716e-2 +vn -0.19155808 -0.97886962 7.1552581e-2 +vn -5.5918068e-2 -0.80716478 0.58767184 +vn -4.2864995e-3 -0.62245606 0.78264301 +vn -2.9519211e-2 -0.50531570 0.86242951 +vn 0.10826783 0.25241317 0.96154338 +vn 9.8033115e-2 0.17798956 0.97913698 +vn 5.7147979e-2 2.4169135e-2 0.99807312 +vn 0.15933722 0.61464890 0.77254021 +vn 0.19570969 0.86374830 0.46436687 +vn -0.93205510 0.26375735 0.24840562 +vn -0.18184047 -0.98327941 9.7795989e-3 +vn -0.16848670 -0.65714449 -0.73469269 +vn -0.18803896 -0.83510825 -0.51694831 +vn -0.19108631 -0.87891006 -0.43703905 +vn -0.18815220 -0.83578432 -0.51581326 +vn 1.6630156e-2 8.3436815e-2 -0.99637430 +vn -0.13719588 0.39382702 -0.90888810 +vn -0.97456860 -0.12685784 -0.18472449 +vn -0.15530685 0.84457329 -0.51242146 +vn 0.94992723 0.27914026 -0.14042429 +vn 0.96309393 0.25197581 -9.4648153e-2 +vn -0.15426328 0.58227477 -0.79822236 +vn 0.96474395 0.26192009 -2.5825874e-2 +vn -0.19004415 0.52255675 -0.83115441 +vn -0.13126681 0.96807269 0.21355160 +vn -0.98709666 -4.1785255e-2 -0.15457743 +vn -0.96848691 -0.11760066 -0.21955224 +vn 0.15402644 -0.54563129 -0.82374896 +vn 0.18617846 -0.81743537 -0.54510274 +vn 0.98670433 0.12170596 -0.10771358 +vn 0.99711333 7.2326136e-2 -2.3107033e-2 +vn 0.97096541 0.19159250 0.14324278 +vn 0.95244055 0.23377198 0.19546782 +vn -1.9866984e-2 0.74697511 0.66455511 +vn -0.99219789 1.5954338e-2 0.12364792 +vn -0.98431163 -0.17618005 9.5500325e-3 +vn -0.94609450 -0.28772828 -0.14871998 +vn -0.94135284 -0.23465302 -0.24247224 +vn -0.95161577 -0.30718290 8.1293032e-3 +vn -0.94317941 -0.32063740 -8.7202405e-2 +vn -0.99401068 -9.6355579e-2 -5.1559436e-2 +vn -0.99375470 -0.10629291 3.3961821e-2 +vn -0.12513768 2.4167362e-2 0.99184500 +vn -0.10801656 2.8636689e-2 0.99373657 +vn 0.95339739 0.25662444 0.15867358 +vn 0.99859905 4.0043736e-2 3.4589610e-2 +vn 0.95928338 0.27118783 7.8946517e-2 +vn 0.98458479 5.5942418e-2 0.16572036 +vn 0.93205510 0.26375735 0.24840562 +vn -0.18281587 0.98238161 -3.8790888e-2 +vn -0.18692559 0.65404939 0.73299265 +vn -0.16166379 0.43847253 0.88408521 +vn -0.98536176 -9.0571823e-2 0.14442627 +vn -0.19570969 0.86374830 0.46436687 +vn -0.15933722 0.61464890 0.77254021 +vn -5.7147979e-2 2.4169135e-2 0.99807312 +vn -9.8033115e-2 0.17798956 0.97913698 +vn -0.10826783 0.25241317 0.96154338 +vn 2.9519211e-2 -0.50531570 0.86242951 +vn 4.2864995e-3 -0.62245606 0.78264301 +vn 5.5918068e-2 -0.80716478 0.58767184 +vn 0.19155808 -0.97886962 7.1552581e-2 +vn 0.19300782 -0.98065558 -3.2597716e-2 +vn 0.16852767 -0.97232355 0.16181884 +vn 0.18184047 -0.98327941 9.7795989e-3 +vn 0.16848670 -0.65714449 -0.73469269 +vn 0.18803896 -0.83510825 -0.51694831 +vn 0.19108631 -0.87891006 -0.43703905 +vn 0.18815220 -0.83578432 -0.51581326 +vn 2.4742800e-2 0.98097420 0.19255497 +vn -1.6554586e-2 0.99948645 2.7436735e-2 +vn -9.1334161e-4 0.26939050 -0.96303059 +vn 7.6530180e-2 -2.4991621e-2 -0.99675401 +vn 0.10786456 -3.4518997e-2 -0.99356614 +vn 5.9380461e-2 0.11356819 -0.99175412 +vn 0.29020955 0.64174311 0.70989027 +vn -0.92252471 0.24634952 0.29708595 +vn 0.30128161 0.31021810 0.90166187 +vn 0.10295218 0.98819006 -0.11349565 +vn 0.96804321 -1.5047200e-2 -0.25033164 +vn -0.20915343 0.38253084 -0.89995833 +vn -1.4637965e-2 0.88669544 -0.46212220 +vn 0.28853598 5.0335211e-2 0.95614505 +vn 0.29331522 -1.5737164e-2 0.95588625 +vn 0.98516670 -0.10720482 -0.13399138 +vn 0.36970179 0.53133853 0.76223353 +vn 0.33356126 0.58633061 0.73820952 +vn 0.99160556 4.6632134e-2 -0.12059793 +vn 0.90122719 -0.19734139 -0.38580557 +vn 0.93419609 -8.5368174e-2 -0.34639565 +vn 0.20617705 0.94233084 0.26363536 +vn -0.96376767 0.17426321 0.20195101 +vn -0.98792430 3.6705175e-2 0.15052680 +vn -0.88548763 0.13716209 0.44395744 +vn 2.4517408e-2 -0.89282141 0.44974307 +vn 0.22073620 -0.40844192 0.88569223 +vn 0.30295694 0.30982652 0.90123505 +vn -2.5640279e-2 -0.95050657 0.30964470 +vn -4.9312187e-2 -0.97310220 0.22503425 +vn -0.29538793 -0.38776438 -0.87314647 +vn -0.28472414 -0.15321960 -0.94628532 +vn -0.29030221 -0.23636547 -0.92728420 +vn -0.28986452 -0.65586079 -0.69701161 +vn -0.96473997 0.21847912 0.14677757 +vn -0.28927382 -0.18867372 -0.93846837 +vn -0.26090378 -0.75257854 -0.60461125 +vn 0.89229083 -2.0305099e-2 -0.45100418 +vn -0.31796225 -0.34609857 -0.88267536 +vn -0.22442603 0.43201889 -0.87349450 +vn 0.17298763 0.97309571 0.15218415 +vn 0.18314242 0.97539743 0.12271392 +vn -7.4462028e-2 0.76701073 -0.63729894 +vn -0.85696768 0.29387992 0.42336862 +vn 1.8797612e-2 0.88554546 -0.46417227 +vn 0.92031485 0.24748713 0.30293678 +vn 0.21435382 0.38159823 -0.89913027 +vn -0.10551459 0.98853921 -0.10796717 +vn -0.96704169 -1.4352143e-2 -0.25421326 +vn -0.30840718 0.30213200 0.90199848 +vn -0.29681264 0.63415876 0.71396423 +vn -0.29650602 5.6376909e-2 0.95336553 +vn -0.30025628 -1.1271945e-2 0.95379196 +vn 0.88096359 0.14027636 0.45191337 +vn -0.37788610 0.52484766 0.76271688 +vn -0.34053137 0.57990863 0.74009754 +vn 0.85234179 0.29649458 0.43081833 +vn 0.98761911 3.7356187e-2 0.15235818 +vn 0.96312351 0.17507612 0.20430727 +vn -0.20887113 0.94061473 0.26761311 +vn -0.93234535 -8.5825804e-2 -0.35123508 +vn -0.89821533 -0.19996076 -0.39143954 +vn -0.98484500 -0.10814103 -0.13559444 +vn -2.5822564e-2 -0.89025874 0.45472252 +vn -0.22640247 -0.39695148 0.88947819 +vn -0.30907743 0.31520490 0.89728313 +vn 2.5541339e-2 -0.94957520 0.31249732 +vn 4.9870652e-2 -0.97261640 0.22700276 +vn 0.30066470 -0.38561795 -0.87229555 +vn 0.28987997 -0.15515817 -0.94440222 +vn 0.29613205 -0.23772555 -0.92509047 +vn 0.29346255 -0.65304298 -0.69815084 +vn -0.88995231 -2.0428681e-2 -0.45559583 +vn 0.29495082 -0.19091846 -0.93624471 +vn 0.26485860 -0.75094711 -0.60492013 +vn 0.96410321 0.21974600 0.14905269 +vn 0.32305224 -0.34402296 -0.88163794 +vn 0.23018301 0.43216550 -0.87192245 +vn -0.17434991 0.97266510 0.15337765 +vn -0.18429097 0.97515560 0.12291623 +vn 7.7794525e-2 0.76436131 -0.64007797 +vn -0.99142389 4.7130113e-2 -0.12189105 +vn -0.97954471 -0.20107248 -7.8757149e-3 +vn -0.89847160 -0.41999722 0.12787149 +vn 0.57021663 -0.71399769 -0.40627613 +vn 0.69499574 -0.51765266 0.49901567 +vn 4.1654568e-2 0.47246282 0.88036571 +vn 0.97936068 0.20159166 1.4610582e-2 +vn 0.44004589 -0.11173880 0.89099610 +vn 0.92891606 0.36187339 -7.8502287e-2 +vn 0.50721424 -0.22665077 0.83148250 +vn -3.3054599e-2 0.84472710 0.53417554 +vn -6.9420253e-4 0.99429301 0.10668146 +vn -0.97401617 -0.21275677 -7.7634110e-2 +vn 3.1756209e-2 0.99949526 8.8194617e-4 +vn 1.9959337e-2 0.99102283 0.13219445 +vn -0.97254451 -0.13912818 -0.18654901 +vn 0.11887387 0.95287976 -0.27908630 +vn 0.19443121 0.77805137 -0.59735464 +vn 0.39069767 -0.78288047 -0.48420398 +vn 0.97539274 0.21007069 6.6927644e-2 +vn 0.43244953 -0.78340048 -0.44639791 +vn 0.45618203 -0.82424227 -0.33544393 +vn 0.97684719 0.15686220 0.14547788 +vn 0.44508046 -0.52943269 -0.72222186 +vn 0.32786327 0.22170247 -0.91834290 +vn -0.97935868 0.20160139 1.4610448e-2 +vn -0.92891247 0.36188252 -7.8502710e-2 +vn -0.57022170 -0.71399406 -0.40627539 +vn -0.69499968 -0.51764519 0.49901793 +vn 3.3063283e-2 0.84472687 0.53417538 +vn -4.1650212e-2 0.47246301 0.88036581 +vn -0.44004524 -0.11173543 0.89099685 +vn -0.50721614 -0.22664572 0.83148271 +vn 0.89846784 -0.42000530 0.12787134 +vn 0.97954268 -0.20108236 -7.8754665e-3 +vn 7.0407571e-4 0.99429322 0.10667945 +vn 0.97401402 -0.21276672 -7.7633833e-2 +vn -3.1746547e-2 0.99949556 8.8103009e-4 +vn -1.9949809e-2 0.99102263 0.13219740 +vn 0.97254315 -0.13913801 -0.18654874 +vn -0.11886459 0.95288093 -0.27908625 +vn -0.39070533 -0.78287641 -0.48420438 +vn -0.43245717 -0.78339604 -0.44639830 +vn -0.45619103 -0.82423891 -0.33543995 +vn -0.44508567 -0.52942913 -0.72222125 +vn -0.32786110 0.22170370 -0.91834338 +vn -0.97684573 0.15687184 0.14547729 +vn -0.97539061 0.21008059 6.6927579e-2 +vn -0.19442349 0.77805298 -0.59735506 +vn -4.7429215e-2 -0.98765307 0.14930467 +vn -0.18302169 -0.81391764 -0.55139925 +vn -0.21119024 -0.17044177 -0.96246989 +vn -0.10464655 0.60102549 -0.79234933 +vn 5.7326493e-2 0.98600493 -0.15655014 +vn 0.17904259 0.81872803 0.54555308 +vn 0.20871816 0.16918378 0.96323080 +vn 0.11629273 -0.60294297 0.78926281 +vn 0.38447718 0.36345603 -0.84857352 +vn 0.77919536 -0.21977674 -0.58698618 +vn 0.57612498 0.79108161 -0.20559644 +vn 0.91017965 -0.41174918 -4.5117815e-2 +vn 0.48649419 0.83642328 0.25242720 +vn 0.82235561 -0.35590000 0.44392165 +vn 0.31045704 0.60135166 0.73620147 +vn 0.25555905 -0.14100913 0.95645491 +vn 0.29429292 -0.95495224 3.8182510e-2 +vn 0.32045532 -0.68426147 -0.65505315 +vn 0.15841542 3.3211810e-5 -0.98737255 +vn -0.10346758 0.70216244 -0.70445892 +vn -0.24943049 0.96828781 -1.4253150e-2 +vn -0.31973039 0.71497010 0.62176381 +vn -0.19323869 3.3744840e-2 0.98057131 +vn 9.9479133e-2 -0.68785094 0.71900277 +vn 4.3779538e-2 -0.98759102 0.15082220 +vn -0.13837990 -0.59823886 0.78927896 +vn -0.23619740 0.16924838 0.95685201 +vn -0.19511049 0.81577757 0.54446199 +vn -5.4087174e-2 0.98598549 -0.15782011 +vn 0.12154295 0.59809530 -0.79215486 +vn 0.22958017 -0.17019440 -0.95829370 +vn 0.19449779 -0.81187875 -0.55047571 +vn -0.26912852 -0.19719412 0.94270054 +vn -0.82736690 -0.34962770 0.43957308 +vn -0.47461240 0.45770965 0.75182774 +vn -0.54326713 0.80364400 0.24293445 +vn -0.91014055 -0.41183354 -4.5136696e-2 +vn -0.57596707 0.79106740 -0.20609294 +vn -0.77913163 -0.21982729 -0.58705184 +vn -0.38441554 0.36310589 -0.84875132 +vn -0.29429417 -0.95495186 3.8182364e-2 +vn -9.9510807e-2 -0.68782079 0.71902723 +vn 8.9970442e-2 -0.13310266 0.98701013 +vn 0.11781382 0.69132823 0.71287108 +vn 0.24444574 0.96901832 -3.5352080e-2 +vn 0.10377140 0.70183020 -0.70474525 +vn -0.15843649 -3.6091805e-5 -0.98736917 +vn -0.32045627 -0.68426135 -0.65505281 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.97420318 -9.3009574e-2 -0.20561465 +vn -0.18699970 0.11816216 -0.97522757 +vn -0.18699970 0.11816216 -0.97522757 +vn -0.18699970 0.11816216 -0.97522757 +vn 0.97426834 -9.2999864e-2 -0.20531008 +vn 0.97426834 -9.2999864e-2 -0.20531008 +vn -0.20923177 -0.63435850 -0.74418503 +vn -0.20923177 -0.63435850 -0.74418503 +vn -0.20923177 -0.63435850 -0.74418503 +vn 0.97439605 -9.2796269e-2 -0.20479548 +vn 0.97439605 -9.2796269e-2 -0.20479548 +vn 0.97439605 -9.2796269e-2 -0.20479548 +vn -4.9143443e-2 0.79682468 -0.60220873 +vn -4.9143443e-2 0.79682468 -0.60220873 +vn -4.9143443e-2 0.79682468 -0.60220873 +vn 0.97451865 -9.2593156e-2 -0.20430345 +vn 0.97451865 -9.2593156e-2 -0.20430345 +vn 0.97451865 -9.2593156e-2 -0.20430345 +vn -0.10449053 -0.98928481 -0.10196710 +vn -0.10449053 -0.98928481 -0.10196710 +vn -0.10449053 -0.98928481 -0.10196710 +vn 0.97476106 -9.2086388e-2 -0.20337397 +vn 0.97476106 -9.2086388e-2 -0.20337397 +vn 0.97476106 -9.2086388e-2 -0.20337397 +vn 0.10380269 0.99023915 9.3013031e-2 +vn 0.10380269 0.99023915 9.3013031e-2 +vn 0.10380269 0.99023915 9.3013031e-2 +vn 0.97484728 -9.1786685e-2 -0.20309600 +vn 0.97484728 -9.1786685e-2 -0.20309600 +vn 0.97484728 -9.1786685e-2 -0.20309600 +vn 6.0503283e-2 -0.79850926 0.59893432 +vn 6.0503283e-2 -0.79850926 0.59893432 +vn 6.0503283e-2 -0.79850926 0.59893432 +vn 0.97498461 -9.1479833e-2 -0.20257455 +vn 0.97498461 -9.1479833e-2 -0.20257455 +vn 0.20067939 0.63709004 0.74420700 +vn 0.20067939 0.63709004 0.74420700 +vn 0.20067939 0.63709004 0.74420700 +vn 0.97490928 -9.1489891e-2 -0.20293222 +vn 0.18902843 -0.11890491 0.97474606 +vn 0.18902843 -0.11890491 0.97474606 +vn 0.18902843 -0.11890491 0.97474606 +vn -0.97412831 -9.2926084e-2 -0.20600672 +vn -0.21623509 -0.11448041 0.96960643 +vn -0.21623509 -0.11448041 0.96960643 +vn -0.21623509 -0.11448041 0.96960643 +vn -0.97411538 -9.3125329e-2 -0.20597791 +vn -0.97411538 -9.3125329e-2 -0.20597791 +vn -0.97411538 -9.3125329e-2 -0.20597791 +vn -7.6064008e-2 -0.79585604 0.60068912 +vn -7.6064008e-2 -0.79585604 0.60068912 +vn -7.6064008e-2 -0.79585604 0.60068912 +vn -0.97420462 -9.2913878e-2 -0.20565109 +vn -0.97420462 -9.2913878e-2 -0.20565109 +vn -0.22239280 0.63403982 0.74063145 +vn -0.22239280 0.63403982 0.74063145 +vn -0.22239280 0.63403982 0.74063145 +vn -0.97407780 -9.3328387e-2 -0.20606370 +vn -0.97407780 -9.3328387e-2 -0.20606370 +vn -0.97407780 -9.3328387e-2 -0.20606370 +vn -0.10744435 0.98981400 9.3402107e-2 +vn -0.10744435 0.98981400 9.3402107e-2 +vn -0.10744435 0.98981400 9.3402107e-2 +vn -0.97392217 -9.3665178e-2 -0.20664568 +vn -0.97392217 -9.3665178e-2 -0.20664568 +vn -0.97392217 -9.3665178e-2 -0.20664568 +vn 0.10699176 -0.98904719 -0.10167801 +vn 0.10699176 -0.98904719 -0.10167801 +vn 0.10699176 -0.98904719 -0.10167801 +vn -0.97383703 -9.3793857e-2 -0.20698831 +vn -0.97383703 -9.3793857e-2 -0.20698831 +vn -0.97383703 -9.3793857e-2 -0.20698831 +vn 6.3240493e-2 0.79488000 -0.60346203 +vn 6.3240493e-2 0.79488000 -0.60346203 +vn 6.3240493e-2 0.79488000 -0.60346203 +vn -0.97374754 -9.3923137e-2 -0.20735037 +vn -0.97374754 -9.3923137e-2 -0.20735037 +vn 0.22374813 -0.63221575 -0.74178165 +vn 0.22374813 -0.63221575 -0.74178165 +vn 0.22374813 -0.63221575 -0.74178165 +vn -0.97368064 -9.3934190e-2 -0.20765927 +vn 0.20665127 0.11572884 -0.97154624 +vn 0.20665127 0.11572884 -0.97154624 +vn 0.20665127 0.11572884 -0.97154624 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 0.0000000e+0 +g Ar_SmallBow_mimiyala_D_default +usemtl default +s 1 +f 1/334/1 3/268/3 2/267/2 +f 2/267/2 3/268/3 1/334/1 +f 4/90/4 6/92/6 5/83/5 +f 4/90/4 10/104/10 6/92/6 +f 5/81/5 8/85/8 4/90/4 +f 5/81/5 37/71/37 8/85/8 +f 6/92/6 7/90/7 5/83/5 +f 6/92/6 12/104/12 7/90/7 +f 7/90/7 12/104/12 9/99/9 +f 7/90/7 13/85/13 5/81/5 +f 8/85/8 9/99/9 4/90/4 +f 8/85/8 14/95/14 9/99/9 +f 8/85/8 22/117/22 14/95/14 +f 8/85/8 28/100/28 22/117/22 +f 8/85/8 34/79/34 28/100/28 +f 8/85/8 37/71/37 34/79/34 +f 9/99/9 10/104/10 4/90/4 +f 9/99/9 13/85/13 7/90/7 +f 9/99/9 14/95/14 13/85/13 +f 9/99/9 192/105/192 10/101/10 +f 10/104/10 11/103/11 6/92/6 +f 10/101/10 190/110/190 11/103/11 +f 10/101/10 191/112/191 190/110/190 +f 10/101/10 192/105/192 191/112/191 +f 11/103/11 12/104/12 6/92/6 +f 11/103/11 190/110/190 12/101/12 +f 12/101/12 192/105/192 9/99/9 +f 13/85/13 37/71/37 5/81/5 +f 14/95/14 15/117/15 13/85/13 +f 14/95/14 16/114/16 15/117/15 +f 14/95/14 22/117/22 16/114/16 +f 15/117/15 28/100/28 13/85/13 +f 15/117/15 29/122/29 28/100/28 +f 15/117/15 30/139/30 29/122/29 +f 16/114/16 17/132/17 15/117/15 +f 16/114/16 18/142/18 17/132/17 +f 16/114/16 23/132/23 18/142/18 +f 17/132/17 30/139/30 15/117/15 +f 18/142/18 19/166/19 17/132/17 +f 18/142/18 20/158/20 19/166/19 +f 18/142/18 24/166/24 20/158/20 +f 19/166/19 30/139/30 17/132/17 +f 19/166/19 31/150/31 30/139/30 +f 20/158/20 21/221/21 19/166/19 +f 20/158/20 268/198/268 21/221/21 +f 21/221/21 26/203/26 19/166/19 +f 21/221/21 268/198/268 240/219/240 +f 21/221/21 271/224/271 26/203/26 +f 22/117/22 23/132/23 16/114/16 +f 22/117/22 30/139/30 23/132/23 +f 23/132/23 24/166/24 18/142/18 +f 23/132/23 30/139/30 24/166/24 +f 24/166/24 25/221/25 20/158/20 +f 24/166/24 26/203/26 25/221/25 +f 24/166/24 27/175/27 26/203/26 +f 24/166/24 33/150/33 27/175/27 +f 25/221/25 268/198/268 20/158/20 +f 25/221/25 269/236/269 240/219/240 +f 25/221/25 270/242/270 269/236/269 +f 25/221/25 271/224/271 270/242/270 +f 26/203/26 27/175/27 19/166/19 +f 26/203/26 271/224/271 25/221/25 +f 27/175/27 31/150/31 19/166/19 +f 27/175/27 32/153/32 31/150/31 +f 27/175/27 33/150/33 32/153/32 +f 28/100/28 29/122/29 22/117/22 +f 28/100/28 34/79/34 13/85/13 +f 29/122/29 30/139/30 22/117/22 +f 30/139/30 33/150/33 24/166/24 +f 30/139/30 35/140/35 33/150/33 +f 31/150/31 35/140/35 30/139/30 +f 31/150/31 36/146/36 35/140/35 +f 32/153/32 36/146/36 31/150/31 +f 33/150/33 36/146/36 32/153/32 +f 34/79/34 37/71/37 13/85/13 +f 35/140/35 36/146/36 33/150/33 +f 38/362/38 40/340/40 39/355/39 +f 38/362/38 44/342/44 40/340/40 +f 38/362/38 53/376/53 44/342/44 +f 38/362/38 54/359/54 52/369/52 +f 39/355/39 54/359/54 38/362/38 +f 40/340/40 41/338/41 39/355/39 +f 40/340/40 71/319/71 41/338/41 +f 41/338/41 42/340/42 39/355/39 +f 41/338/41 71/319/71 42/340/42 +f 42/340/42 43/362/43 39/355/39 +f 42/340/42 44/342/44 43/362/43 +f 42/340/42 62/316/62 44/342/44 +f 42/340/42 71/319/71 62/316/62 +f 43/362/43 54/359/54 39/355/39 +f 44/342/44 45/376/45 43/362/43 +f 44/342/44 68/316/68 40/340/40 +f 44/342/44 69/309/69 68/316/68 +f 44/78/44 98/68/98 45/113/45 +f 44/78/44 109/62/109 98/68/98 +f 44/78/44 110/72/110 109/62/109 +f 44/78/44 112/62/112 110/72/110 +f 44/78/44 113/68/113 112/62/112 +f 45/376/45 46/369/46 43/362/43 +f 45/376/45 47/383/47 46/369/46 +f 45/113/45 100/136/100 47/133/47 +f 46/369/46 54/359/54 43/362/43 +f 46/369/46 55/361/55 54/359/54 +f 47/383/47 48/372/48 46/369/46 +f 47/383/47 49/381/49 48/372/48 +f 47/383/47 51/372/51 49/381/49 +f 47/383/47 52/369/52 51/372/51 +f 47/383/47 53/376/53 52/369/52 +f 47/133/47 106/136/106 53/113/53 +f 47/133/47 114/151/114 106/136/106 +f 48/372/48 55/361/55 46/369/46 +f 48/372/48 56/373/56 55/361/55 +f 49/381/49 50/384/50 48/372/48 +f 49/381/49 51/372/51 50/384/50 +f 50/384/50 56/373/56 48/372/48 +f 50/384/50 57/382/57 56/373/56 +f 50/384/50 63/373/63 57/382/57 +f 51/372/51 63/373/63 50/384/50 +f 52/369/52 53/376/53 38/362/38 +f 52/369/52 55/361/55 51/372/51 +f 53/113/53 113/68/113 44/78/44 +f 54/359/54 55/361/55 52/369/52 +f 55/361/55 63/373/63 51/372/51 +f 55/361/55 74/358/74 63/373/63 +f 56/373/56 74/358/74 55/361/55 +f 57/382/57 58/365/58 56/373/56 +f 57/382/57 59/370/59 58/365/58 +f 57/287/57 245/261/245 59/301/59 +f 57/287/57 251/238/251 245/261/245 +f 58/365/58 74/358/74 56/373/56 +f 59/370/59 60/356/60 58/365/58 +f 59/370/59 61/346/61 60/356/60 +f 59/301/59 254/326/254 61/336/61 +f 60/356/60 73/353/73 58/365/58 +f 61/346/61 62/331/62 60/356/60 +f 61/346/61 69/335/69 62/331/62 +f 61/346/61 70/339/70 69/335/69 +f 61/336/61 254/326/254 70/344/70 +f 62/316/62 69/309/69 44/342/44 +f 62/331/62 72/347/72 60/356/60 +f 63/373/63 64/365/64 57/382/57 +f 63/373/63 74/358/74 64/365/64 +f 64/365/64 65/370/65 57/382/57 +f 64/365/64 66/356/66 65/370/65 +f 64/365/64 73/353/73 66/356/66 +f 64/365/64 74/358/74 73/353/73 +f 65/301/65 250/261/250 57/287/57 +f 65/301/65 274/326/274 249/271/249 +f 66/356/66 67/346/67 65/370/65 +f 66/356/66 68/331/68 67/346/67 +f 66/356/66 72/347/72 68/331/68 +f 66/356/66 73/353/73 72/347/72 +f 67/336/67 274/326/274 65/301/65 +f 68/331/68 69/335/69 67/346/67 +f 68/316/68 71/319/71 40/340/40 +f 68/331/68 72/347/72 71/329/71 +f 69/335/69 70/339/70 67/346/67 +f 70/344/70 274/326/274 67/336/67 +f 70/344/70 275/330/275 274/326/274 +f 71/329/71 72/347/72 62/331/62 +f 72/347/72 73/353/73 60/356/60 +f 73/353/73 74/358/74 58/365/58 +f 75/208/75 77/213/77 76/197/76 +f 75/208/75 81/220/81 77/213/77 +f 75/208/75 89/209/89 81/220/81 +f 75/208/75 91/202/91 89/209/89 +f 76/197/76 90/200/90 75/208/75 +f 76/197/76 94/188/94 90/200/90 +f 76/197/76 96/173/96 94/188/94 +f 76/197/76 97/190/97 96/173/96 +f 77/213/77 78/206/78 76/197/76 +f 77/213/77 79/197/79 78/206/78 +f 77/213/77 80/208/80 79/197/79 +f 77/213/77 81/220/81 80/208/80 +f 78/206/78 97/190/97 76/197/76 +f 79/197/79 97/190/97 78/206/78 +f 80/208/80 90/200/90 79/197/79 +f 80/208/80 91/202/91 90/200/90 +f 81/220/81 82/209/82 80/208/80 +f 81/220/81 83/218/83 82/209/82 +f 81/220/81 89/209/89 83/218/83 +f 82/209/82 91/202/91 80/208/80 +f 82/209/82 92/193/92 91/202/91 +f 83/218/83 84/211/84 82/209/82 +f 83/218/83 89/209/89 84/211/84 +f 84/211/84 85/201/85 82/209/82 +f 84/211/84 86/205/86 85/201/85 +f 84/211/84 88/201/88 86/205/86 +f 84/211/84 89/209/89 88/201/88 +f 85/201/85 92/193/92 82/209/82 +f 85/201/85 93/185/93 92/193/92 +f 86/205/86 87/196/87 85/201/85 +f 86/205/86 88/201/88 87/196/87 +f 87/196/87 93/185/93 85/201/85 +f 88/201/88 93/185/93 87/196/87 +f 89/209/89 92/193/92 88/201/88 +f 90/200/90 91/202/91 75/208/75 +f 90/200/90 94/188/94 79/197/79 +f 91/202/91 92/193/92 89/209/89 +f 92/193/92 93/185/93 88/201/88 +f 94/188/94 95/173/95 79/197/79 +f 94/188/94 104/168/104 95/173/95 +f 95/173/95 97/190/97 79/197/79 +f 95/173/95 104/168/104 103/148/103 +f 95/173/95 116/184/116 97/190/97 +f 96/173/96 104/168/104 94/188/94 +f 96/173/96 115/171/115 102/149/102 +f 96/173/96 117/184/117 115/171/115 +f 97/190/97 117/184/117 96/173/96 +f 97/190/97 118/189/118 117/184/117 +f 98/68/98 99/106/99 45/113/45 +f 98/68/98 163/73/163 99/106/99 +f 99/106/99 100/136/100 45/113/45 +f 99/106/99 101/143/101 100/136/100 +f 99/106/99 147/128/147 101/143/101 +f 99/106/99 156/120/156 147/128/147 +f 99/106/99 164/98/164 156/120/156 +f 100/136/100 114/151/114 47/133/47 +f 101/143/101 102/149/102 100/136/100 +f 101/143/101 103/148/103 102/149/102 +f 101/143/101 105/149/105 103/148/103 +f 101/143/101 106/136/106 105/149/105 +f 101/143/101 107/106/107 106/136/106 +f 101/143/101 108/128/108 107/106/107 +f 101/143/101 152/147/152 108/128/108 +f 101/143/101 153/152/153 152/147/152 +f 101/143/101 155/147/155 153/152/153 +f 102/149/102 103/148/103 96/173/96 +f 102/149/102 114/151/114 100/136/100 +f 102/149/102 115/171/115 114/151/114 +f 103/148/103 104/168/104 96/173/96 +f 103/148/103 105/149/105 95/173/95 +f 105/149/105 115/171/115 95/173/95 +f 106/136/106 107/106/107 53/113/53 +f 106/136/106 114/151/114 105/149/105 +f 107/106/107 113/68/113 53/113/53 +f 107/106/107 163/73/163 113/68/113 +f 107/106/107 164/98/164 163/73/163 +f 108/128/108 148/144/148 146/129/146 +f 108/128/108 151/157/151 143/161/143 +f 108/128/108 152/147/152 151/157/151 +f 108/128/108 156/120/156 107/106/107 +f 109/62/109 161/51/161 98/68/98 +f 110/72/110 111/70/111 109/62/109 +f 110/72/110 112/62/112 111/70/111 +f 111/70/111 159/56/159 109/62/109 +f 111/70/111 167/55/167 159/56/159 +f 111/70/111 180/66/180 167/55/167 +f 112/62/112 165/51/165 160/46/160 +f 112/62/112 166/56/166 111/70/111 +f 113/68/113 163/73/163 162/57/162 +f 113/68/113 165/51/165 112/62/112 +f 114/151/114 115/171/115 105/149/105 +f 115/171/115 116/184/116 95/173/95 +f 115/171/115 120/172/120 116/184/116 +f 116/184/116 118/189/118 97/190/97 +f 116/184/116 119/174/119 118/189/118 +f 116/184/116 120/172/120 119/174/119 +f 117/184/117 120/172/120 115/171/115 +f 118/189/118 119/174/119 117/184/117 +f 119/174/119 120/172/120 117/184/117 +f 121/248/121 123/239/123 122/250/122 +f 121/248/121 126/250/126 123/239/123 +f 121/248/121 132/253/132 126/250/126 +f 121/248/121 133/247/133 132/253/132 +f 121/248/121 135/253/135 133/247/133 +f 122/250/122 127/245/127 125/256/125 +f 122/250/122 135/253/135 121/248/121 +f 122/250/122 144/254/144 135/253/135 +f 123/239/123 124/235/124 122/250/122 +f 123/239/123 131/233/131 124/235/124 +f 124/235/124 127/245/127 122/250/122 +f 124/235/124 131/233/131 130/231/130 +f 124/235/124 137/210/137 127/245/127 +f 125/256/125 127/245/127 126/250/126 +f 125/256/125 136/257/136 122/250/122 +f 126/250/126 128/235/128 123/239/123 +f 126/250/126 136/257/136 125/256/125 +f 126/250/126 144/254/144 136/257/136 +f 127/245/127 128/235/128 126/250/126 +f 127/245/127 129/210/129 128/235/128 +f 127/245/127 223/258/223 129/210/129 +f 127/245/127 226/258/226 222/273/222 +f 128/235/128 131/233/131 123/239/123 +f 129/210/129 130/231/130 128/235/128 +f 129/210/129 138/215/138 130/231/130 +f 129/210/129 139/204/139 138/215/138 +f 129/210/129 142/214/142 141/199/141 +f 129/210/129 143/161/143 139/204/139 +f 129/210/129 227/225/227 142/214/142 +f 130/231/130 131/233/131 128/235/128 +f 130/231/130 137/210/137 124/235/124 +f 130/231/130 138/215/138 137/210/137 +f 132/253/132 144/254/144 126/250/126 +f 132/253/132 145/249/145 144/254/144 +f 133/247/133 134/243/134 132/253/132 +f 133/247/133 135/253/135 134/243/134 +f 134/243/134 145/249/145 132/253/132 +f 135/253/135 145/249/145 134/243/134 +f 136/257/136 144/254/144 122/250/122 +f 137/210/137 226/258/226 127/245/127 +f 137/210/137 227/225/227 226/258/226 +f 138/215/138 139/204/139 137/210/137 +f 139/204/139 140/161/140 137/210/137 +f 139/204/139 150/178/150 140/161/140 +f 140/161/140 141/199/141 137/210/137 +f 140/161/140 149/167/149 141/199/141 +f 140/161/140 151/157/151 147/128/147 +f 141/199/141 142/214/142 137/210/137 +f 141/199/141 143/161/143 129/210/129 +f 141/199/141 149/167/149 143/161/143 +f 142/214/142 227/225/227 137/210/137 +f 143/161/143 148/144/148 108/128/108 +f 143/161/143 149/167/149 148/144/148 +f 143/161/143 150/178/150 139/204/139 +f 143/161/143 151/157/151 150/178/150 +f 144/254/144 145/249/145 135/253/135 +f 146/129/146 148/144/148 147/128/147 +f 146/129/146 156/120/156 108/128/108 +f 147/128/147 148/144/148 140/161/140 +f 147/128/147 155/147/155 101/143/101 +f 147/128/147 156/120/156 146/129/146 +f 148/144/148 149/167/149 140/161/140 +f 150/178/150 151/157/151 140/161/140 +f 151/157/151 155/147/155 147/128/147 +f 151/157/151 157/165/157 155/147/155 +f 152/147/152 157/165/157 151/157/151 +f 152/147/152 158/176/158 157/165/157 +f 153/152/153 154/160/154 152/147/152 +f 153/152/153 155/147/155 154/160/154 +f 154/160/154 158/176/158 152/147/152 +f 155/147/155 158/176/158 154/160/154 +f 156/120/156 164/98/164 107/106/107 +f 157/165/157 158/176/158 155/147/155 +f 159/56/159 160/46/160 109/62/109 +f 159/56/159 236/35/236 160/46/160 +f 160/46/160 161/51/161 109/62/109 +f 160/46/160 166/56/166 112/62/112 +f 160/46/160 236/35/236 166/56/166 +f 160/46/160 238/20/238 161/51/161 +f 161/51/161 162/57/162 98/68/98 +f 161/51/161 238/20/238 237/27/237 +f 161/51/161 239/43/239 162/57/162 +f 162/57/162 163/73/163 98/68/98 +f 162/57/162 165/51/165 113/68/113 +f 162/57/162 239/43/239 165/51/165 +f 163/73/163 164/98/164 99/106/99 +f 165/51/165 238/20/238 160/46/160 +f 165/51/165 239/43/239 237/27/237 +f 166/56/166 176/55/176 111/70/111 +f 166/56/166 236/35/236 168/39/168 +f 167/55/167 168/39/168 159/56/159 +f 167/55/167 169/44/169 168/39/168 +f 167/55/167 177/52/177 169/44/169 +f 167/55/167 178/60/178 177/52/177 +f 167/55/167 180/66/180 178/60/178 +f 168/39/168 176/55/176 166/56/166 +f 168/39/168 236/35/236 159/56/159 +f 169/44/169 170/26/170 168/39/168 +f 169/44/169 171/30/171 170/26/170 +f 169/44/169 177/52/177 171/30/171 +f 170/26/170 175/44/175 168/39/168 +f 171/30/171 172/15/172 170/26/170 +f 171/30/171 173/10/173 172/15/172 +f 171/30/171 183/24/183 173/10/173 +f 172/15/172 174/30/174 170/26/170 +f 173/10/173 174/30/174 172/15/172 +f 173/10/173 181/24/181 174/30/174 +f 173/10/173 184/11/184 181/24/181 +f 174/30/174 175/44/175 170/26/170 +f 174/30/174 177/52/177 175/44/175 +f 174/30/174 179/41/179 177/52/177 +f 174/30/174 181/24/181 179/41/179 +f 175/44/175 176/55/176 168/39/168 +f 175/44/175 177/52/177 176/55/176 +f 176/55/176 180/66/180 111/70/111 +f 177/52/177 178/60/178 176/55/176 +f 177/52/177 179/41/179 171/30/171 +f 178/60/178 180/66/180 176/55/176 +f 179/41/179 183/24/183 171/30/171 +f 181/24/181 182/32/182 179/41/179 +f 181/24/181 185/25/185 182/32/182 +f 182/32/182 183/24/183 179/41/179 +f 182/32/182 187/25/187 183/24/183 +f 183/24/183 184/11/184 173/10/173 +f 183/24/183 187/25/187 184/11/184 +f 184/11/184 185/25/185 181/24/181 +f 184/11/184 188/14/188 185/25/185 +f 185/25/185 186/38/186 182/32/182 +f 185/25/185 189/23/189 186/38/186 +f 186/38/186 187/25/187 182/32/182 +f 186/38/186 189/23/189 187/25/187 +f 187/25/187 188/14/188 184/11/184 +f 187/25/187 189/23/189 188/14/188 +f 188/14/188 189/23/189 185/25/185 +f 190/110/190 191/112/191 12/101/12 +f 191/112/191 192/105/192 12/101/12 +f 193/364/193 195/366/195 194/357/194 +f 193/364/193 197/357/197 195/366/195 +f 193/364/193 204/349/204 197/357/197 +f 194/357/194 199/349/199 193/364/193 +f 194/357/194 205/351/205 198/350/198 +f 194/357/194 206/354/206 205/351/205 +f 195/366/195 196/367/196 194/357/194 +f 195/366/195 197/357/197 196/367/196 +f 196/367/196 206/354/206 194/357/194 +f 196/367/196 207/360/207 206/354/206 +f 196/367/196 208/354/208 207/360/207 +f 197/357/197 204/349/204 198/350/198 +f 197/357/197 208/354/208 196/367/196 +f 198/350/198 199/349/199 194/357/194 +f 198/350/198 205/351/205 197/357/197 +f 198/350/198 235/341/235 199/349/199 +f 199/349/199 200/368/200 193/364/193 +f 199/349/199 213/363/213 200/368/200 +f 199/349/199 234/324/234 211/327/211 +f 199/349/199 235/341/235 234/324/234 +f 200/368/200 201/375/201 193/364/193 +f 200/368/200 202/385/202 201/375/201 +f 200/368/200 218/380/218 202/385/202 +f 201/375/201 203/368/203 193/364/193 +f 202/385/202 203/368/203 201/375/201 +f 202/385/202 218/380/218 203/368/203 +f 203/368/203 204/349/204 193/364/193 +f 203/368/203 216/363/216 204/349/204 +f 203/368/203 218/380/218 214/377/214 +f 204/349/204 216/363/216 212/352/212 +f 204/349/204 235/341/235 198/350/198 +f 205/351/205 208/354/208 197/357/197 +f 205/351/205 209/348/209 208/354/208 +f 206/354/206 209/348/209 205/351/205 +f 207/360/207 209/348/209 206/354/206 +f 208/354/208 209/348/209 207/360/207 +f 210/343/210 212/352/212 211/327/211 +f 210/343/210 217/327/217 212/352/212 +f 210/343/210 225/325/225 217/327/217 +f 211/327/211 212/352/212 199/349/199 +f 211/327/211 225/325/225 210/343/210 +f 211/327/211 233/280/233 223/258/223 +f 211/327/211 234/324/234 233/280/233 +f 212/352/212 213/363/213 199/349/199 +f 212/352/212 217/327/217 204/349/204 +f 212/352/212 219/371/219 213/363/213 +f 213/363/213 214/377/214 200/368/200 +f 213/363/213 215/378/215 214/377/214 +f 213/363/213 221/379/221 215/378/215 +f 214/377/214 216/363/216 203/368/203 +f 214/377/214 218/380/218 200/368/200 +f 215/378/215 216/363/216 214/377/214 +f 215/378/215 221/379/221 216/363/216 +f 216/363/216 219/371/219 212/352/212 +f 216/363/216 220/374/220 219/371/219 +f 216/363/216 221/379/221 220/374/220 +f 217/327/217 225/325/225 224/294/224 +f 217/327/217 234/324/234 204/349/204 +f 219/371/219 220/374/220 213/363/213 +f 220/374/220 221/379/221 213/363/213 +f 222/273/222 223/258/223 127/245/127 +f 222/273/222 224/294/224 223/258/223 +f 222/273/222 226/258/226 224/294/224 +f 223/258/223 224/294/224 211/327/211 +f 223/258/223 227/225/227 129/210/129 +f 223/258/223 228/246/228 227/225/227 +f 223/258/223 232/266/232 228/246/228 +f 223/258/223 233/280/233 232/266/232 +f 224/294/224 225/325/225 211/327/211 +f 224/294/224 226/258/226 217/327/217 +f 226/258/226 233/280/233 217/327/217 +f 227/225/227 228/246/228 226/258/226 +f 228/246/228 229/266/229 226/258/226 +f 228/246/228 230/262/230 229/266/229 +f 228/246/228 232/266/232 230/262/230 +f 229/266/229 233/280/233 226/258/226 +f 230/262/230 231/286/231 229/266/229 +f 230/262/230 232/266/232 231/286/231 +f 231/286/231 233/280/233 229/266/229 +f 232/266/232 233/280/233 231/286/231 +f 233/280/233 234/324/234 217/327/217 +f 234/324/234 235/341/235 204/349/204 +f 237/27/237 238/20/238 165/51/165 +f 237/27/237 239/43/239 161/51/161 +f 240/219/240 242/207/242 241/244/241 +f 240/219/240 244/244/244 242/207/242 +f 240/219/240 267/236/267 21/221/21 +f 240/219/240 268/198/268 25/221/25 +f 240/219/240 269/236/269 244/244/244 +f 241/244/241 248/222/248 247/232/247 +f 241/244/241 267/236/267 240/219/240 +f 242/207/242 243/212/243 241/244/241 +f 242/207/242 244/244/244 243/212/243 +f 243/212/243 248/222/248 241/244/241 +f 244/244/244 248/222/248 243/212/243 +f 244/244/244 256/293/256 246/271/246 +f 244/244/244 257/276/257 256/293/256 +f 244/244/244 264/265/264 257/276/257 +f 244/244/244 266/263/266 264/265/264 +f 244/244/244 269/236/269 266/263/266 +f 245/261/245 246/271/246 59/301/59 +f 245/261/245 247/232/247 246/271/246 +f 245/261/245 253/223/253 247/232/247 +f 246/271/246 247/232/247 244/244/244 +f 246/271/246 254/326/254 59/301/59 +f 246/271/246 255/297/255 254/326/254 +f 246/271/246 256/293/256 255/297/255 +f 247/232/247 248/222/248 244/244/244 +f 247/232/247 249/271/249 241/244/241 +f 247/232/247 250/261/250 249/271/249 +f 247/232/247 253/223/253 250/261/250 +f 249/271/249 250/261/250 65/301/65 +f 249/271/249 256/293/256 241/244/241 +f 249/271/249 274/326/274 255/297/255 +f 250/261/250 251/238/251 57/287/57 +f 250/261/250 252/230/252 251/238/251 +f 250/261/250 253/223/253 252/230/252 +f 251/238/251 252/230/252 245/261/245 +f 252/230/252 253/223/253 245/261/245 +f 254/326/254 275/330/275 70/344/70 +f 255/297/255 256/293/256 249/271/249 +f 255/297/255 275/330/275 254/326/254 +f 256/293/256 257/276/257 241/244/241 +f 257/276/257 258/265/258 241/244/241 +f 257/276/257 259/282/259 258/265/258 +f 257/276/257 264/265/264 259/282/259 +f 258/265/258 266/263/266 241/244/241 +f 259/282/259 260/279/260 258/265/258 +f 259/282/259 261/285/261 260/279/260 +f 259/282/259 263/279/263 261/285/261 +f 259/282/259 264/265/264 263/279/263 +f 260/279/260 265/272/265 258/265/258 +f 260/279/260 272/283/272 265/272/265 +f 260/279/260 273/284/273 272/283/272 +f 261/285/261 262/292/262 260/279/260 +f 261/285/261 263/279/263 262/292/262 +f 262/292/262 273/284/273 260/279/260 +f 263/279/263 273/284/273 262/292/262 +f 264/265/264 265/272/265 263/279/263 +f 264/265/264 266/263/266 265/272/265 +f 265/272/265 266/263/266 258/265/258 +f 265/272/265 272/283/272 263/279/263 +f 266/263/266 267/236/267 241/244/241 +f 266/263/266 270/242/270 267/236/267 +f 267/236/267 270/242/270 21/221/21 +f 269/236/269 270/242/270 266/263/266 +f 270/242/270 271/224/271 21/221/21 +f 272/283/272 273/284/273 263/279/263 +f 274/326/274 275/330/275 255/297/255 +f 276/187/276 278/195/278 277/181/277 +f 276/186/276 280/179/280 278/194/278 +f 276/187/276 281/138/281 280/180/280 +f 276/186/276 301/162/301 281/138/281 +f 277/182/277 289/138/289 276/187/276 +f 278/195/278 279/177/279 277/181/277 +f 278/194/278 280/179/280 279/177/279 +f 279/177/279 289/138/289 277/182/277 +f 280/180/280 281/138/281 279/177/279 +f 281/138/281 282/169/282 279/177/279 +f 281/138/281 283/163/283 282/169/282 +f 281/138/281 284/137/284 283/163/283 +f 281/138/281 291/119/291 284/137/284 +f 281/138/281 292/121/292 291/119/291 +f 281/138/281 293/134/293 292/121/292 +f 281/138/281 301/162/301 293/134/293 +f 282/170/282 289/138/289 279/177/279 +f 283/163/283 289/138/289 282/170/282 +f 284/137/284 285/156/285 283/163/283 +f 284/137/284 286/154/286 285/156/285 +f 284/137/284 287/135/287 286/154/286 +f 284/137/284 290/123/290 287/135/287 +f 284/137/284 291/119/291 290/123/290 +f 285/155/285 288/137/288 283/163/283 +f 286/154/286 288/137/288 285/155/285 +f 287/135/287 288/137/288 286/154/286 +f 287/135/287 290/123/290 288/137/288 +f 288/137/288 289/138/289 283/163/283 +f 288/137/288 300/119/300 289/138/289 +f 289/138/289 299/121/299 298/134/298 +f 289/138/289 300/119/300 299/121/299 +f 289/138/289 301/164/301 276/187/276 +f 290/123/290 300/119/300 288/137/288 +f 290/123/290 333/111/333 300/119/300 +f 291/119/291 333/111/333 290/123/290 +f 291/119/291 334/102/334 333/111/333 +f 292/121/292 311/91/311 291/119/291 +f 293/134/293 294/124/294 292/121/292 +f 293/134/293 295/159/295 294/124/294 +f 293/134/293 302/183/302 295/159/295 +f 294/124/294 310/115/310 292/121/292 +f 295/159/295 296/131/296 294/124/294 +f 295/159/295 297/124/297 296/131/296 +f 295/159/295 298/134/298 297/124/297 +f 295/159/295 302/183/302 298/134/298 +f 296/131/296 303/127/303 294/124/294 +f 297/124/297 303/127/303 296/131/296 +f 297/124/297 304/125/304 303/127/303 +f 297/124/297 305/116/305 304/125/304 +f 297/124/297 310/115/310 305/116/305 +f 298/134/298 299/121/299 297/124/297 +f 298/134/298 301/164/301 289/138/289 +f 298/134/298 302/183/302 301/164/301 +f 299/121/299 310/115/310 297/124/297 +f 300/119/300 309/91/309 299/121/299 +f 300/119/300 334/102/334 307/82/307 +f 301/162/301 302/183/302 293/134/293 +f 303/127/303 304/125/304 294/124/294 +f 304/125/304 305/116/305 294/124/294 +f 305/116/305 310/115/310 294/124/294 +f 306/42/306 308/65/308 307/82/307 +f 306/42/306 330/45/330 308/65/308 +f 307/82/307 309/91/309 300/119/300 +f 307/82/307 320/49/320 306/42/306 +f 307/82/307 331/67/331 319/59/319 +f 307/82/307 332/80/332 331/67/331 +f 307/82/307 335/88/335 332/80/332 +f 308/65/308 309/91/309 307/82/307 +f 308/65/308 317/86/317 309/91/309 +f 308/65/308 330/45/330 316/74/316 +f 309/91/309 310/115/310 299/121/299 +f 309/91/309 318/97/318 310/115/310 +f 310/115/310 311/91/311 292/121/292 +f 310/115/310 318/97/318 311/91/311 +f 311/91/311 312/82/312 291/119/291 +f 311/91/311 313/65/313 312/82/312 +f 311/91/311 317/86/317 313/65/313 +f 311/91/311 318/97/318 317/86/317 +f 312/82/312 320/48/320 319/59/319 +f 312/82/312 334/102/334 291/119/291 +f 312/82/312 335/88/335 334/102/334 +f 313/65/313 314/42/314 312/82/312 +f 313/65/313 315/45/315 314/42/314 +f 313/65/313 316/74/316 315/45/315 +f 313/65/313 317/86/317 316/74/316 +f 314/42/314 320/48/320 312/82/312 +f 314/42/314 321/28/321 320/48/320 +f 314/42/314 322/9/322 321/28/321 +f 314/42/314 323/8/323 322/9/322 +f 314/42/314 324/2/324 323/8/323 +f 315/45/315 324/2/324 314/42/314 +f 315/45/315 325/5/325 324/2/324 +f 315/45/315 326/16/326 325/5/325 +f 315/45/315 327/18/327 326/16/326 +f 315/45/315 328/36/328 327/18/327 +f 315/45/315 329/58/329 328/36/328 +f 316/74/316 317/86/317 308/65/308 +f 316/74/316 329/58/329 315/45/315 +f 316/74/316 330/45/330 329/58/329 +f 317/86/317 318/97/318 309/91/309 +f 319/59/319 320/49/320 307/82/307 +f 319/59/319 331/67/331 312/82/312 +f 320/49/320 321/29/321 306/42/306 +f 321/29/321 322/9/322 306/42/306 +f 322/9/322 323/7/323 306/42/306 +f 323/7/323 324/1/324 306/42/306 +f 324/1/324 330/45/330 306/42/306 +f 325/6/325 330/45/330 324/1/324 +f 326/17/326 330/45/330 325/6/325 +f 327/19/327 330/45/330 326/17/326 +f 328/37/328 330/45/330 327/19/327 +f 329/58/329 330/45/330 328/37/328 +f 331/67/331 332/80/332 312/82/312 +f 332/80/332 335/88/335 312/82/312 +f 333/111/333 334/102/334 300/119/300 +f 334/102/334 335/88/335 307/82/307 +f 336/177/336 338/179/338 337/194/337 +f 336/177/336 347/138/347 338/180/338 +f 336/177/336 392/169/392 347/138/347 +f 337/195/337 340/181/340 336/177/336 +f 338/179/338 339/186/339 337/194/337 +f 338/180/338 347/138/347 339/187/339 +f 339/187/339 340/181/340 337/195/337 +f 339/187/339 341/138/341 340/182/340 +f 339/187/339 342/164/342 341/138/341 +f 339/186/339 347/138/347 342/162/342 +f 340/182/340 341/138/341 336/177/336 +f 341/138/341 351/119/351 350/137/350 +f 341/138/341 352/121/352 351/119/351 +f 341/138/341 392/170/392 336/177/336 +f 341/138/341 393/163/393 392/170/392 +f 342/164/342 343/134/343 341/138/341 +f 342/164/342 344/183/344 343/134/343 +f 342/162/342 346/134/346 344/183/344 +f 342/162/342 347/138/347 346/134/346 +f 343/134/343 352/121/352 341/138/341 +f 343/134/343 353/124/353 352/121/352 +f 344/183/344 345/159/345 343/134/343 +f 344/183/344 346/134/346 345/159/345 +f 345/159/345 353/124/353 343/134/343 +f 345/159/345 354/131/354 353/124/353 +f 345/159/345 355/124/355 354/131/354 +f 346/134/346 355/124/355 345/159/345 +f 346/134/346 356/121/356 355/124/355 +f 347/138/347 356/121/356 346/134/346 +f 347/138/347 357/119/357 356/121/356 +f 347/138/347 358/137/358 357/119/357 +f 347/138/347 393/163/393 358/137/358 +f 348/135/348 350/137/350 349/123/349 +f 348/135/348 395/154/395 350/137/350 +f 349/123/349 358/137/358 348/135/348 +f 349/123/349 387/111/387 357/119/357 +f 350/137/350 351/119/351 349/123/349 +f 350/137/350 393/163/393 341/138/341 +f 350/137/350 394/155/394 393/163/393 +f 350/137/350 395/154/395 394/155/394 +f 351/119/351 387/111/387 349/123/349 +f 351/119/351 388/102/388 387/111/387 +f 352/121/352 365/91/365 351/119/351 +f 353/124/353 363/115/363 352/121/352 +f 353/124/353 364/116/364 363/115/363 +f 353/124/353 391/125/391 364/116/364 +f 354/131/354 390/127/390 353/124/353 +f 355/124/355 390/127/390 354/131/354 +f 355/124/355 391/125/391 390/127/390 +f 356/121/356 363/115/363 355/124/355 +f 357/119/357 358/137/358 349/123/349 +f 357/119/357 362/91/362 356/121/356 +f 357/119/357 388/102/388 360/82/360 +f 358/137/358 395/154/395 348/135/348 +f 359/42/359 361/65/361 360/82/360 +f 359/42/359 373/45/373 361/65/361 +f 359/42/359 379/2/379 373/45/373 +f 359/42/359 380/8/380 379/2/379 +f 359/42/359 381/9/381 380/8/380 +f 359/42/359 382/28/382 381/9/381 +f 359/42/359 383/48/383 382/28/382 +f 360/82/360 362/91/362 357/119/357 +f 360/82/360 383/48/383 359/42/359 +f 360/82/360 384/59/384 383/48/383 +f 360/82/360 385/67/385 384/59/384 +f 360/82/360 386/80/386 385/67/385 +f 360/82/360 389/88/389 386/80/386 +f 361/65/361 362/91/362 360/82/360 +f 361/65/361 371/86/371 362/91/362 +f 361/65/361 373/45/373 370/74/370 +f 362/91/362 363/115/363 356/121/356 +f 362/91/362 372/97/372 363/115/363 +f 363/115/363 364/116/364 355/124/355 +f 363/115/363 365/91/365 352/121/352 +f 363/115/363 372/97/372 365/91/365 +f 364/116/364 391/125/391 355/124/355 +f 365/91/365 366/82/366 351/119/351 +f 365/91/365 367/65/367 366/82/366 +f 365/91/365 371/86/371 367/65/367 +f 365/91/365 372/97/372 371/86/371 +f 366/82/366 388/102/388 351/119/351 +f 366/82/366 389/88/389 388/102/388 +f 367/65/367 368/42/368 366/82/366 +f 367/65/367 369/45/369 368/42/368 +f 367/65/367 370/74/370 369/45/369 +f 367/65/367 371/86/371 370/74/370 +f 368/42/368 383/49/383 366/82/366 +f 369/45/369 379/1/379 368/42/368 +f 370/74/370 371/86/371 361/65/361 +f 370/74/370 374/58/374 369/45/369 +f 371/86/371 372/97/372 362/91/362 +f 373/45/373 374/58/374 370/74/370 +f 373/45/373 375/36/375 374/58/374 +f 373/45/373 376/18/376 375/36/375 +f 373/45/373 377/16/377 376/18/376 +f 373/45/373 378/5/378 377/16/377 +f 373/45/373 379/2/379 378/5/378 +f 374/58/374 375/37/375 369/45/369 +f 375/37/375 376/19/376 369/45/369 +f 376/19/376 377/17/377 369/45/369 +f 377/17/377 378/6/378 369/45/369 +f 378/6/378 379/1/379 369/45/369 +f 379/1/379 380/7/380 368/42/368 +f 380/7/380 381/9/381 368/42/368 +f 381/9/381 382/29/382 368/42/368 +f 382/29/382 383/49/383 368/42/368 +f 383/49/383 384/59/384 366/82/366 +f 384/59/384 385/67/385 366/82/366 +f 385/67/385 386/80/386 366/82/366 +f 386/80/386 389/88/389 366/82/366 +f 387/111/387 388/102/388 357/119/357 +f 388/102/388 389/88/389 360/82/360 +f 390/127/390 391/125/391 353/124/353 +f 392/169/392 393/163/393 347/138/347 +f 393/163/393 394/156/394 358/137/358 +f 394/156/394 395/154/395 358/137/358 +f 396/323/396 398/337/398 397/302/397 +f 396/323/396 400/302/400 398/337/398 +f 396/323/396 408/310/408 400/302/400 +f 396/323/396 433/310/433 407/318/407 +f 397/302/397 433/310/433 396/323/396 +f 398/337/398 399/345/399 397/302/397 +f 398/337/398 400/302/400 399/345/399 +f 399/345/399 401/332/401 397/302/397 +f 400/302/400 401/332/401 399/345/399 +f 400/302/400 402/317/402 401/332/401 +f 400/302/400 408/310/408 405/288/405 +f 400/302/400 410/298/410 402/317/402 +f 401/332/401 402/317/402 397/302/397 +f 402/317/402 412/298/412 397/302/397 +f 403/295/403 405/288/405 404/305/404 +f 403/295/403 417/289/417 405/288/405 +f 404/304/404 414/288/414 403/295/403 +f 405/288/405 406/311/406 404/305/404 +f 405/288/405 407/318/407 406/311/406 +f 405/288/405 408/310/408 407/318/407 +f 405/288/405 409/277/409 400/302/400 +f 405/288/405 415/251/415 409/277/409 +f 405/288/405 416/270/416 415/251/415 +f 405/288/405 417/289/417 416/270/416 +f 406/314/406 414/288/414 404/304/404 +f 407/318/407 408/310/408 396/323/396 +f 407/318/407 414/288/414 406/314/406 +f 407/318/407 433/310/433 414/288/414 +f 409/277/409 410/298/410 400/302/400 +f 409/277/409 420/278/420 410/298/410 +f 409/277/409 421/264/421 420/278/420 +f 409/277/409 422/255/422 421/264/421 +f 409/277/409 425/237/425 422/255/422 +f 409/277/409 426/227/426 425/237/425 +f 410/298/410 411/328/411 402/317/402 +f 410/298/410 432/320/432 411/328/411 +f 411/328/411 412/298/412 402/317/402 +f 411/328/411 432/320/432 412/298/412 +f 412/298/412 413/277/413 397/302/397 +f 412/298/412 420/278/420 413/277/413 +f 412/298/412 423/281/423 420/278/420 +f 412/298/412 424/303/424 423/281/423 +f 412/298/412 431/315/431 424/303/424 +f 412/298/412 432/320/432 431/315/431 +f 413/277/413 414/288/414 397/302/397 +f 413/277/413 415/252/415 414/288/414 +f 413/277/413 418/234/418 415/252/415 +f 413/277/413 419/226/419 418/234/418 +f 413/277/413 426/227/426 419/226/419 +f 414/288/414 417/289/417 403/295/403 +f 414/288/414 433/310/433 397/302/397 +f 415/252/415 416/269/416 414/288/414 +f 415/251/415 418/234/418 409/277/409 +f 416/269/416 417/289/417 414/288/414 +f 418/234/418 419/226/419 409/277/409 +f 419/226/419 426/227/426 409/277/409 +f 420/278/420 421/264/421 413/277/413 +f 420/278/420 423/281/423 410/298/410 +f 421/264/421 422/255/422 413/277/413 +f 422/255/422 425/237/425 413/277/413 +f 423/281/423 427/303/427 410/298/410 +f 423/281/423 428/296/428 427/303/427 +f 424/303/424 428/296/428 423/281/423 +f 424/303/424 429/306/429 428/296/428 +f 424/303/424 430/313/430 429/306/429 +f 424/303/424 431/315/431 430/313/430 +f 425/237/425 426/227/426 413/277/413 +f 427/303/427 431/315/431 410/298/410 +f 428/296/428 429/306/429 427/303/427 +f 429/306/429 430/312/430 427/303/427 +f 430/312/430 431/315/431 427/303/427 +f 431/315/431 432/320/432 410/298/410 +f 434/317/434 436/332/436 435/302/435 +f 434/317/434 438/302/438 436/332/436 +f 434/317/434 450/298/450 438/302/438 +f 435/302/435 446/310/446 443/288/443 +f 435/302/435 448/298/448 434/317/434 +f 436/332/436 437/345/437 435/302/435 +f 436/332/436 438/302/438 437/345/437 +f 437/345/437 439/337/439 435/302/435 +f 438/302/438 439/337/439 437/345/437 +f 438/302/438 440/323/440 439/337/439 +f 438/302/438 471/310/471 440/323/440 +f 439/337/439 440/323/440 435/302/435 +f 440/323/440 446/310/446 435/302/435 +f 440/323/440 471/310/471 445/318/445 +f 441/295/441 443/288/443 442/304/442 +f 441/295/441 455/289/455 443/288/443 +f 442/305/442 452/288/452 441/295/441 +f 443/288/443 444/314/444 442/304/442 +f 443/288/443 445/318/445 444/314/444 +f 443/288/443 446/310/446 445/318/445 +f 443/288/443 447/277/447 435/302/435 +f 443/288/443 453/252/453 447/277/447 +f 443/288/443 454/269/454 453/252/453 +f 443/288/443 455/289/455 454/269/454 +f 444/311/444 452/288/452 442/305/442 +f 445/318/445 446/310/446 440/323/440 +f 445/318/445 452/288/452 444/311/444 +f 445/318/445 471/310/471 452/288/452 +f 447/277/447 448/298/448 435/302/435 +f 447/277/447 458/278/458 448/298/448 +f 447/277/447 459/264/459 458/278/458 +f 447/277/447 460/255/460 459/264/459 +f 447/277/447 463/237/463 460/255/460 +f 447/277/447 464/227/464 463/237/463 +f 448/298/448 449/328/449 434/317/434 +f 448/298/448 470/320/470 449/328/449 +f 449/328/449 450/298/450 434/317/434 +f 449/328/449 470/320/470 450/298/450 +f 450/298/450 451/277/451 438/302/438 +f 450/298/450 458/278/458 451/277/451 +f 450/298/450 461/281/461 458/278/458 +f 450/298/450 462/303/462 461/281/461 +f 450/298/450 469/315/469 462/303/462 +f 450/298/450 470/320/470 469/315/469 +f 451/277/451 452/288/452 438/302/438 +f 451/277/451 453/251/453 452/288/452 +f 451/277/451 456/234/456 453/251/453 +f 451/277/451 457/226/457 456/234/456 +f 451/277/451 464/227/464 457/226/457 +f 452/288/452 455/289/455 441/295/441 +f 452/288/452 471/310/471 438/302/438 +f 453/251/453 454/270/454 452/288/452 +f 453/252/453 456/234/456 447/277/447 +f 454/270/454 455/289/455 452/288/452 +f 456/234/456 457/226/457 447/277/447 +f 457/226/457 464/227/464 447/277/447 +f 458/278/458 459/264/459 451/277/451 +f 458/278/458 461/281/461 448/298/448 +f 459/264/459 460/255/460 451/277/451 +f 460/255/460 463/237/463 451/277/451 +f 461/281/461 465/303/465 448/298/448 +f 461/281/461 466/296/466 465/303/465 +f 462/303/462 466/296/466 461/281/461 +f 462/303/462 467/306/467 466/296/466 +f 462/303/462 468/312/468 467/306/467 +f 462/303/462 469/315/469 468/312/468 +f 463/237/463 464/227/464 451/277/451 +f 465/303/465 469/315/469 448/298/448 +f 466/296/466 467/306/467 465/303/465 +f 467/306/467 468/313/468 465/303/465 +f 468/313/468 469/315/469 465/303/465 +f 469/315/469 470/320/470 448/298/448 +f 472/50/472 474/61/474 473/47/473 +f 472/50/472 478/13/478 476/4/476 +f 472/50/472 489/77/489 474/61/474 +f 473/47/473 478/13/478 472/50/472 +f 473/47/473 480/31/480 478/13/478 +f 474/61/474 475/40/475 473/47/473 +f 474/61/474 479/47/479 475/40/475 +f 474/61/474 489/77/489 477/50/477 +f 475/40/475 480/31/480 473/47/473 +f 476/3/476 478/12/478 477/50/477 +f 476/4/476 481/21/481 472/50/472 +f 477/50/477 479/47/479 474/61/474 +f 477/50/477 481/22/481 476/3/476 +f 477/50/477 482/34/482 481/22/481 +f 477/50/477 490/69/490 482/34/482 +f 478/12/478 479/47/479 477/50/477 +f 478/12/478 480/31/480 479/47/479 +f 479/47/479 480/31/480 475/40/475 +f 481/21/481 482/33/482 472/50/472 +f 482/33/482 483/69/483 472/50/472 +f 482/33/482 484/54/484 483/69/483 +f 482/34/482 490/69/490 484/53/484 +f 483/69/483 489/77/489 472/50/472 +f 483/69/483 491/84/491 489/77/489 +f 483/69/483 492/96/492 491/84/491 +f 484/54/484 485/64/485 483/69/483 +f 484/53/484 490/69/490 485/63/485 +f 485/64/485 486/87/486 483/69/483 +f 485/64/485 487/75/487 486/87/486 +f 485/63/485 493/87/493 487/76/487 +f 486/87/486 492/96/492 483/69/483 +f 486/87/486 494/108/494 492/96/492 +f 486/87/486 495/107/495 494/108/494 +f 487/75/487 488/94/488 486/87/486 +f 487/76/487 493/87/493 488/94/488 +f 488/94/488 495/107/495 486/87/486 +f 489/77/489 490/69/490 477/50/477 +f 489/77/489 491/84/491 490/69/490 +f 490/69/490 493/87/493 485/63/485 +f 491/84/491 492/96/492 490/69/490 +f 492/96/492 493/87/493 490/69/490 +f 492/96/492 494/108/494 493/87/493 +f 493/87/493 495/107/495 488/94/488 +f 494/108/494 495/107/495 493/87/493 +f 496/50/496 498/61/498 497/47/497 +f 496/50/496 501/3/501 500/22/500 +f 496/50/496 502/12/502 501/3/501 +f 496/50/496 512/77/512 498/61/498 +f 496/50/496 518/69/518 512/77/512 +f 497/47/497 502/12/502 496/50/496 +f 497/47/497 503/31/503 502/12/502 +f 498/61/498 499/40/499 497/47/497 +f 498/61/498 504/47/504 499/40/499 +f 498/61/498 505/50/505 504/47/504 +f 498/61/498 512/77/512 505/50/505 +f 499/40/499 503/31/503 497/47/497 +f 499/40/499 504/47/504 503/31/503 +f 500/22/500 506/34/506 496/50/496 +f 501/4/501 505/50/505 500/21/500 +f 502/13/502 505/50/505 501/4/501 +f 503/31/503 504/47/504 502/13/502 +f 504/47/504 505/50/505 502/13/502 +f 505/50/505 506/33/506 500/21/500 +f 505/50/505 507/69/507 506/33/506 +f 505/50/505 512/77/512 507/69/507 +f 506/34/506 518/69/518 496/50/496 +f 507/69/507 508/54/508 506/33/506 +f 507/69/507 509/64/509 508/54/508 +f 507/69/507 510/87/510 509/64/509 +f 507/69/507 514/96/514 510/87/510 +f 508/53/508 518/69/518 506/34/506 +f 509/63/509 518/69/518 508/53/508 +f 510/87/510 511/75/511 509/64/509 +f 510/87/510 519/94/519 511/75/511 +f 511/76/511 517/87/517 509/63/509 +f 511/76/511 519/94/519 517/87/517 +f 512/77/512 513/84/513 507/69/507 +f 512/77/512 518/69/518 513/84/513 +f 513/84/513 514/96/514 507/69/507 +f 513/84/513 518/69/518 514/96/514 +f 514/96/514 515/108/515 510/87/510 +f 514/96/514 517/87/517 515/108/515 +f 514/96/514 518/69/518 517/87/517 +f 515/108/515 516/107/516 510/87/510 +f 515/108/515 517/87/517 516/107/516 +f 516/107/516 519/94/519 510/87/510 +f 517/87/517 518/69/518 509/63/509 +f 517/87/517 519/94/519 516/107/516 +f 520/300/576 531/290/523 522/291/585 +f 521/308/581 530/299/522 520/300/574 +f 522/291/587 532/274/524 524/275/597 +f 523/322/592 529/307/521 521/308/579 +f 524/275/599 533/259/525 526/260/608 +f 525/229/605 528/216/520 523/217/593 +f 525/229/604 535/228/527 528/216/520 +f 526/260/610 534/240/526 527/241/612 +f 527/241/614 535/228/527 525/229/603 +f 528/321/520 529/307/521 523/322/591 +f 529/307/521 530/299/522 521/308/580 +f 530/299/522 531/290/523 520/300/575 +f 531/290/523 532/274/524 522/291/586 +f 532/274/524 533/259/525 524/275/598 +f 533/259/525 534/240/526 526/260/609 +f 534/240/526 535/228/527 527/241/613 +f 536/109/528 538/126/530 537/89/529 +f 536/300/528 547/290/539 538/291/530 +f 537/308/529 546/299/538 536/300/528 +f 538/126/530 539/93/531 537/89/529 +f 538/126/530 540/141/532 539/93/531 +f 538/291/530 548/274/540 540/275/532 +f 539/322/531 545/307/537 537/308/529 +f 540/141/532 541/118/533 539/93/531 +f 540/141/532 542/145/534 541/118/533 +f 540/275/532 549/259/541 542/260/534 +f 541/229/533 544/216/536 539/217/531 +f 541/229/533 551/228/543 544/216/536 +f 542/145/534 543/130/535 541/118/533 +f 542/260/534 550/240/542 543/241/535 +f 543/241/535 551/228/543 541/229/533 +f 544/321/536 545/307/537 539/322/531 +f 545/307/537 546/299/538 537/308/529 +f 546/299/538 547/290/539 536/300/528 +f 547/290/539 548/274/540 538/291/530 +f 548/274/540 549/259/541 540/275/532 +f 549/259/541 550/240/542 542/260/534 +f 550/240/542 551/228/543 543/241/535 +f 552/241/618 562/240/546 554/260/627 +f 553/229/624 561/228/545 552/241/616 +f 554/260/629 563/259/547 555/275/633 +f 555/275/635 564/274/548 557/291/645 +f 556/217/639 560/216/544 553/229/622 +f 556/322/641 567/307/551 560/321/544 +f 557/291/647 565/290/549 559/300/654 +f 558/308/652 567/307/551 556/322/640 +f 559/300/656 566/299/550 558/308/650 +f 560/216/544 561/228/545 553/229/623 +f 561/228/545 562/240/546 552/241/617 +f 562/240/546 563/259/547 554/260/628 +f 563/259/547 564/274/548 555/275/634 +f 564/274/548 565/290/549 557/291/646 +f 565/290/549 566/299/550 559/300/655 +f 566/299/550 567/307/551 558/308/651 +f 568/130/552 570/145/554 569/118/553 +f 568/241/552 578/240/562 570/260/554 +f 569/229/553 577/228/561 568/241/552 +f 570/145/554 571/141/555 569/118/553 +f 570/260/554 579/259/563 571/275/555 +f 571/141/555 572/93/556 569/118/553 +f 571/141/555 573/126/557 572/93/556 +f 571/275/555 580/274/564 573/291/557 +f 572/217/556 576/216/560 569/229/553 +f 572/322/556 583/307/567 576/321/560 +f 573/126/557 574/89/558 572/93/556 +f 573/126/557 575/109/559 574/89/558 +f 573/291/557 581/290/565 575/300/559 +f 574/308/558 583/307/567 572/322/556 +f 575/300/559 582/299/566 574/308/558 +f 576/216/560 577/228/561 569/229/553 +f 577/228/561 578/240/562 568/241/552 +f 578/240/562 579/259/563 570/260/554 +f 579/259/563 580/274/564 571/275/555 +f 580/274/564 581/290/565 573/291/557 +f 581/290/565 582/299/566 575/300/559 +f 582/299/566 583/307/567 574/308/558 +f 584/333/657 586/267/568 585/334/659 +f 585/334/660 586/267/568 584/333/658 +f 587/267/569 589/192/571 588/268/570 +f 588/268/570 589/192/571 587/267/569 +f 590/267/572 592/191/663 591/192/661 +f 591/192/662 592/191/664 590/267/572 +s 2 +f 520/109/573 522/126/582 521/89/577 +f 522/126/583 523/93/588 521/89/578 +f 522/126/584 524/141/594 523/93/589 +f 524/141/595 525/118/600 523/93/590 +f 524/141/596 526/145/606 525/118/601 +f 526/145/607 527/130/611 525/118/602 +f 552/130/615 554/145/625 553/118/619 +f 554/145/626 555/141/630 553/118/620 +f 555/141/631 556/93/636 553/118/621 +f 555/141/632 557/126/642 556/93/637 +f 557/126/643 558/89/648 556/93/638 +f 557/126/644 559/109/653 558/89/649 diff --git a/Weapons/Smallbow_Mimiyala.ugh b/Weapons/Smallbow_Mimiyala.ugh new file mode 100644 index 0000000..15d14ba Binary files /dev/null and b/Weapons/Smallbow_Mimiyala.ugh differ diff --git a/Weapons/ar_smallbow_mimiyala_d02.dds.png b/Weapons/ar_smallbow_mimiyala_d02.dds.png new file mode 100644 index 0000000..0870697 Binary files /dev/null and b/Weapons/ar_smallbow_mimiyala_d02.dds.png differ diff --git a/ar_smallbow_mimiyala_d02.dds b/ar_smallbow_mimiyala_d02.dds new file mode 100644 index 0000000..58c8e4d Binary files /dev/null and b/ar_smallbow_mimiyala_d02.dds differ