diff --git a/Apps/SampleData/MultipartVehicle_part1.czml b/Apps/SampleData/MultipartVehicle_part1.czml new file mode 100644 index 000000000000..c9f1d359fd37 --- /dev/null +++ b/Apps/SampleData/MultipartVehicle_part1.czml @@ -0,0 +1,244 @@ +[ + { + "id":"document", + "version":"1.0" + }, + { + "id":"Vehicle", + "availability":"2012-08-04T16:00:00Z/2012-08-04T17:04:54.9962195740191Z", + "label":{ + "fillColor":[ + { + "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", + "rgba":[ + 255,255,0,255 + ] + } + ], + "font":"bold 10pt Segoe UI Semibold", + "horizontalOrigin":"CENTER", + "outlineColor":{ + "rgba":[ + 0,0,0,255 + ] + }, + "pixelOffset":{ + "cartesian2":[ + 0.0,20.0 + ] + }, + "scale":1.0, + "show":[ + { + "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", + "boolean":true + } + ], + "style":"FILL", + "text":"Test Vehicle", + "verticalOrigin":"CENTER" + }, + "model":{ + "gltf":"models/CesiumMilkTruck/CesiumMilkTruck.glb", + "minimumPixelSize":100, + "maximumScale":50 + }, + "orientation" : { + "velocityReference": "#position" + }, + "viewFrom": { + "cartesian": [ -2080, -1715, 779 ] + }, + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 0, 22.5, + 1500, 21.2 + ] + } + }, + "path":{ + "material":{ + "solidColor":{ + "color":{ + "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", + "rgba":[ + 255,255,0,255 + ] + } + } + }, + "width":[ + { + "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", + "number":5.0 + } + ], + "show":[ + { + "interval":"2012-08-04T16:00:00Z/2012-08-04T18:00:00Z", + "boolean":true + } + ] + }, + "position":{ + "interpolationAlgorithm":"LAGRANGE", + "interpolationDegree":1, + "epoch":"2012-08-04T16:00:00Z", + "cartesian":[ + 0.0,-2379754.6637012,-4665332.88013588,3628133.68924173, + 10.0,-2379510.08905552,-4665419.64840452,3628182.20006795, + 20.0,-2379568.4769522,-4665555.3441867,3627970.83323261, + 30.0,-2379638.93786855,-4665691.63561896,3627750.82085873, + 40.0,-2379709.29834665,-4665827.9679646,3627530.80187124, + 50.0,-2379837.28064915,-4665847.7494347,3627422.12874017, + 60.0,-2379624.98289073,-4665907.50853722,3627484.1191848, + 70.0,-2379386.12743523,-4666029.54174431,3627483.83297459, + 80.0,-2379147.26777171,-4666151.56669944,3627483.5403492, + 90.0,-2378908.40390057,-4666273.58340244,3627483.24130864, + 1e2,-2378663.69301645,-4666379.62408751,3627507.14485116, + 110.0,-2378416.29648478,-4666444.93145547,3627584.82610021, + 120.0,-2378184.75115833,-4666458.05260387,3627718.84628509, + 130.0,-2377958.22637221,-4666461.11592729,3627862.42864636, + 140.0,-2377733.79758374,-4666460.508441,3628009.31669747, + 150.0,-2377509.36460154,-4666459.89268533,3628156.19830638, + 160.0,-2377284.92742603,-4666459.26866028,3628303.07347284, + 170.0,-2377060.48605759,-4666458.63636585,3628449.9421966, + 180.0,-2376835.38472681,-4666459.12413084,3628595.78980713, + 190.0,-2376609.71084875,-4666460.58154837,3628740.75156098, + 2e2,-2376384.03277903,-4666462.03069678,3628885.70687201, + 210.0,-2376158.35051806,-4666463.47157605,3629030.65573998, + 220.0,-2375928.48736859,-4666473.69575712,3629167.08552075, + 230.0,-2375685.23921682,-4666516.66377513,3629270.3788586, + 240.0,-2375437.34307768,-4666580.50029931,3629350.0215939, + 250.0,-2375189.01133306,-4666646.99320452,3629426.53515423, + 260.0,-2374940.52675783,-4666719.29042452,3629495.71527129, + 270.0,-2374695.15633549,-4666818.94185605,3629527.91579302, + 280.0,-2374469.42323533,-4666959.02687352,3629495.69349509, + 290.0,-2374249.06659405,-4667105.51477438,3629451.77975513, + 3e2,-2374028.70574724,-4667251.99442379,3629407.85959417, + 310.0,-2373808.3406953,-4667398.46582147,3629363.9330123, + 320.0,-2373585.10773309,-4667542.05948567,3629325.52597676, + 330.0,-2373360.83645524,-4667684.60869937,3629289.10800226, + 340.0,-2373136.5609746,-4667827.1496603,3629252.68360778, + 350.0,-2372912.28129155,-4667969.68236819,3629216.25279339, + 360.0,-2372687.9974065,-4668112.20682281,3629179.81555915, + 370.0,-2372463.70931983,-4668254.72302389,3629143.37190511, + 380.0,-2372239.41703195,-4668397.2309712,3629106.92183136, + 390.0,-2372018.7615611,-4668543.12509124,3629063.76398058, + 4e2,-2371803.72586004,-4668694.25404103,3629010.24868951, + 410.0,-2371587.17705087,-4668844.01756398,3628959.44085712, + 420.0,-2371365.33472237,-4668989.01539779,3628918.13984128, + 430.0,-2371134.7547923,-4669122.83460485,3628896.77687771, + 440.0,-2370898.14635373,-4669248.94021679,3628889.16522147, + 450.0,-2370660.31892949,-4669372.89697404,3628885.07134974, + 460.0,-2370422.47459187,-4669496.82305927,3628881.00796265, + 470.0,-2370184.62606153,-4669620.7408867,3628876.93815788, + 480.0,-2369946.77333888,-4669744.65045611,3628872.86193545, + 490.0,-2369708.91642433,-4669868.55176729,3628868.77929537, + 5e2,-2369471.05531832,-4669992.44482001,3628864.69023764, + 510.0,-2369233.19002126,-4670116.32961405,3628860.59476226, + 520.0,-2368989.65950726,-4670225.94237244,3628878.39787596, + 530.0,-2368742.64810033,-4670324.93393451,3628912.01606989, + 540.0,-2368494.95906007,-4670419.65546435,3628951.51257903, + 550.0,-2368248.2848424,-4670519.53079746,3628983.74302284, + 560.0,-2368001.37437725,-4670618.8319301,3629016.84097985, + 570.0,-2367753.95809484,-4670715.82368808,3629053.19940679, + 580.0,-2367506.53762994,-4670812.80718267,3629089.55141416, + 590.0,-2367259.11298298,-4670909.78241366,3629125.89700192, + 6e2,-2367011.6841544,-4671006.74938092,3629162.23617, + 610.0,-2366764.25114462,-4671103.70808425,3629198.56891833, + 620.0,-2366516.81395411,-4671200.6585235,3629234.89524684, + 630.0,-2366269.37258329,-4671297.60069848,3629271.21515549, + 640.0,-2366021.9270326,-4671394.53460904,3629307.52864419, + 650.0,-2365774.47730247,-4671491.460255,3629343.8357129, + 660.0,-2365527.02339333,-4671588.37763618,3629380.13636155, + 670.0,-2365279.56530564,-4671685.28675242,3629416.43059006, + 680.0,-2365032.10303983,-4671782.18760355,3629452.71839837, + 690.0,-2364784.63659633,-4671879.0801894,3629488.99978644, + 7e2,-2364537.16597558,-4671975.96450979,3629525.27475418, + 710.0,-2364289.69117801,-4672072.84056456,3629561.54330154, + 720.0,-2364042.21220407,-4672169.70835353,3629597.80542845, + 730.0,-2363794.72905419,-4672266.56787654,3629634.06113485, + 740.0,-2363547.2417288,-4672363.41913342,3629670.31042068, + 750.0,-2363299.75022835,-4672460.26212398,3629706.55328587, + 760.0,-2363052.25455328,-4672557.09684808,3629742.78973036, + 770.0,-2362805.96213832,-4672658.44235501,3629772.46055, + 780.0,-2362566.28756432,-4672777.84646024,3629774.74120741, + 790.0,-2362330.01543718,-4672904.47715606,3629765.56158533, + 8e2,-2362093.73913086,-4673031.09958839,3629756.37554393, + 810.0,-2361857.4586458,-4673157.71375702,3629747.18308323, + 820.0,-2361621.17398239,-4673284.31966172,3629737.98420324, + 830.0,-2361379.13396171,-4673398.62592987,3629748.21496888, + 840.0,-2361130.58722369,-4673488.59963461,3629793.74986512, + 850.0,-2360881.58098042,-4673573.14384665,3629846.50583809, + 860.0,-2360632.51954154,-4673657.07225834,3629900.06533886, + 870.0,-2360383.45393477,-4673740.99239963,3629953.61841672, + 880.0,-2360134.38416057,-4673824.90427038,3630007.16507155, + 890.0,-2359885.31021938,-4673908.80787044,3630060.70530326, + 9e2,-2359636.23211162,-4673992.70319966,3630114.23911177, + 910.0,-2359387.14983775,-4674076.5902579,3630167.76649697, + 920.0,-2359138.06339821,-4674160.469045,3630221.28745878, + 930.0,-2358889.14548278,-4674246.80164025,3630271.54165003, + 940.0,-2358640.17887385,-4674332.39488805,3630322.75317441, + 950.0,-2358391.03374684,-4674415.32432296,3630377.46713032, + 960.0,-2358141.88445605,-4674498.24548602,3630432.17466229, + 970.0,-2357892.7310019,-4674581.15837706,3630486.87577026, + 980.0,-2357643.59031994,-4674664.39449658,3630541.13554932, + 990.0,-2357394.48770584,-4674748.44899573,3630594.30439711, + 1e3,-2357145.38092955,-4674832.4952226,3630647.46682079, + 1010.0,-2356896.26999152,-4674916.53317705,3630700.62282028, + 1020.0,-2356647.15489217,-4675000.56285892,3630753.77239547, + 1030.0,-2356398.03563196,-4675084.58426807,3630806.91554629, + 1040.0,-2356148.91221132,-4675168.59740435,3630860.05227262, + 1050.0,-2355899.78463069,-4675252.60226762,3630913.18257437, + 1060.0,-2355650.65289051,-4675336.59885772,3630966.30645147, + 1070.0,-2355401.51699122,-4675420.58717452,3631019.42390381, + 1080.0,-2355152.37693328,-4675504.56721785,3631072.5349313, + 1090.0,-2354903.2327171,-4675588.53898758,3631125.63953384, + 1.1e3,-2354654.08434313,-4675672.50248355,3631178.73771134, + 1110.0,-2354404.86337217,-4675754.50046618,3631234.37690825, + 1120.0,-2354155.84214723,-4675830.29554952,3631297.80148619, + 1130.0,-2353909.99308372,-4675880.61174319,3631391.75187422, + 1140.0,-2353667.55938687,-4675917.7532863,3631500.33400567, + 1150.0,-2353425.14548842,-4675954.80919402,3631608.99321685, + 1160.0,-2353182.7274392,-4675991.85682064,3631717.64599126, + 1170.0,-2352940.30523964,-4676028.89616608,3631826.29232871, + 1180.0,-2352697.87889015,-4676065.92723028,3631934.93222899, + 1190.0,-2352455.44839119,-4676102.95001317,3632043.56569193, + 1.2e3,-2352213.01374317,-4676139.9645147,3632152.19271733, + 1210.0,-2351970.57494653,-4676176.97073479,3632260.81330501, + 1220.0,-2351728.13200169,-4676213.96867339,3632369.42745476, + 1230.0,-2351485.68490907,-4676250.95833043,3632478.03516641, + 1240.0,-2351243.23366913,-4676287.93970586,3632586.63643975, + 1250.0,-2351000.77828228,-4676324.91279958,3632695.2312746, + 1260.0,-2350758.31874895,-4676361.87761156,3632803.81967077, + 1270.0,-2350515.85506957,-4676398.83414172,3632912.40162807, + 1280.0,-2350273.38724458,-4676435.78239001,3633020.9771463, + 1290.0,-2350029.47875804,-4676477.3914753,3633124.49944636, + 1.3e3,-2349785.42349382,-4676519.45587927,3633227.51421022, + 1310.0,-2349541.36408501,-4676561.51200187,3633330.52253589, + 1320.0,-2349297.30053206,-4676603.55984302,3633433.52442318, + 1330.0,-2349053.2328354,-4676645.59940266,3633536.51987191, + 1340.0,-2348809.16099546,-4676687.63068071,3633639.50888189, + 1350.0,-2348565.08501267,-4676729.65367709,3633742.49145297, + 1360.0,-2348321.00488746,-4676771.66839174,3633845.46758493, + 1370.0,-2348076.92062027,-4676813.67482458,3633948.43727762, + 1380.0,-2347832.83221153,-4676855.67297554,3634051.40053084, + 1390.0,-2347588.73966167,-4676897.66284454,3634154.35734442, + 1.4e3,-2347344.64297113,-4676939.64443151,3634257.30771818, + 1410.0,-2347101.04731466,-4676979.96034855,3634362.04616856, + 1420.0,-2346858.26575513,-4677017.5834931,3634469.6847769, + 1430.0,-2346614.99348312,-4677056.89461847,3634575.46081166, + 1440.0,-2346369.55744615,-4677103.7262244,3634672.99207759, + 1450.0,-2346124.8248997,-4677147.9423086,3634773.39569376, + 1460.0,-2345880.74403986,-4677189.73374292,3634876.46090671, + 1470.0,-2345636.65904236,-4677231.51689469,3634979.51967852, + 1480.0,-2345392.56990766,-4677273.29176384,3635082.57200902, + 1490.0,-2345148.47663614,-4677315.05835029,3635185.61789803, + 1.5e3,-2344904.37922829,-4677356.81665397,3635288.65734536 + ] + } + } +] diff --git a/Apps/SampleData/MultipartVehicle_part2.czml b/Apps/SampleData/MultipartVehicle_part2.czml new file mode 100644 index 000000000000..a1a7f69045b5 --- /dev/null +++ b/Apps/SampleData/MultipartVehicle_part2.czml @@ -0,0 +1,174 @@ +[ + { + "id":"document", + "version":"1.0" + }, + { + "id":"Vehicle", + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 3000, 19.9 + ] + } + }, + "position":{ + "interpolationAlgorithm":"LAGRANGE", + "interpolationDegree":1, + "epoch":"2012-08-04T16:00:00Z", + "cartesian":[ + 1510.0,-2344660.2776845,-4677398.56667482,3635391.69035084, + 1520.0,-2344416.17200522,-4677440.30841274,3635494.71691428, + 1530.0,-2344172.06219089,-4677482.04186768,3635597.7370355, + 1540.0,-2343927.94824192,-4677523.76703957,3635700.75071434, + 1550.0,-2343683.83015876,-4677565.48392832,3635803.75795058, + 1560.0,-2343439.70794184,-4677607.19253388,3635906.75874406, + 1570.0,-2343195.58159159,-4677648.89285615,3636009.75309461, + 1580.0,-2342951.45110844,-4677690.58489508,3636112.74100204, + 1590.0,-2342707.31649283,-4677732.2686506,3636215.72246616, + 1.6e3,-2342463.17774519,-4677773.94412263,3636318.6974868, + 1610.0,-2342219.03486595,-4677815.61131108,3636421.66606378, + 1620.0,-2341974.88785554,-4677857.2702159,3636524.6281969, + 1630.0,-2341730.7367144,-4677898.92083702,3636627.583886, + 1640.0,-2341486.58144295,-4677940.56317435,3636730.5331309, + 1650.0,-2341242.42204163,-4677982.19722784,3636833.4759314, + 1660.0,-2340998.25851088,-4678023.8229974,3636936.41228734, + 1670.0,-2340754.09085112,-4678065.44048297,3637039.34219853, + 1680.0,-2340509.91906279,-4678107.04968447,3637142.26566479, + 1690.0,-2340265.74314632,-4678148.65060182,3637245.18268593, + 1.7e3,-2340021.56310214,-4678190.24323497,3637348.09326179, + 1710.0,-2339777.37893069,-4678231.82758383,3637450.99739218, + 1720.0,-2339533.1906324,-4678273.40364834,3637553.8950769, + 1730.0,-2339288.99820769,-4678314.97142841,3637656.7863158, + 1740.0,-2339044.80165702,-4678356.530924,3637759.67110868, + 1750.0,-2338800.60098079,-4678398.082135,3637862.54945536, + 1760.0,-2338554.70615885,-4678446.63979812,3637957.53985359, + 1770.0,-2338307.34044549,-4678501.27725608,3638045.68346556, + 1780.0,-2338059.970607,-4678555.90643107,3638133.82063425, + 1790.0,-2337812.5966438,-4678610.527323,3638221.9513595, + 1.8e3,-2337565.21855632,-4678665.13993177,3638310.07564116, + 1810.0,-2337317.836345,-4678719.74425728,3638398.19347906, + 1820.0,-2337070.45001029,-4678774.34029945,3638486.30487305, + 1830.0,-2336823.05955262,-4678828.92805817,3638574.40982299, + 1840.0,-2336575.66497242,-4678883.50753334,3638662.50832871, + 1850.0,-2336327.1545835,-4678945.50581105,3638741.82308353, + 1860.0,-2336079.08419082,-4679004.31007705,3638824.91716907, + 1870.0,-2335832.84388937,-4679053.5438294,3638919.0484984, + 1880.0,-2335586.22540763,-4679104.36395041,3639011.37515412, + 1890.0,-2335339.10405755,-4679157.40812923,3639101.16216049, + 1.9e3,-2335091.77487812,-4679211.48259624,3639189.74611699, + 1910.0,-2334844.32516034,-4679266.14231747,3639277.63977539, + 1920.0,-2334596.87132354,-4679320.79375442,3639365.52698836, + 1930.0,-2334349.41336814,-4679375.436907,3639453.40775576, + 1940.0,-2334101.95129458,-4679430.07177509,3639541.28207743, + 1950.0,-2333854.48510331,-4679484.69835863,3639629.14995324, + 1960.0,-2333607.01479475,-4679539.31665749,3639717.011383, + 1970.0,-2333359.54036938,-4679593.9266716,3639804.86636658, + 1980.0,-2333112.06182757,-4679648.52840084,3639892.71490381, + 1990.0,-2332864.57916982,-4679703.12184515,3639980.55699455, + 2e3,-2332617.09239653,-4679757.70700441,3640068.39263865, + 2010.0,-2332369.60150815,-4679812.28387853,3640156.22183593, + 2020.0,-2332122.10650513,-4679866.85246742,3640244.04458626, + 2030.0,-2331874.6073879,-4679921.41277097,3640331.86088948, + 2040.0,-2331627.10415689,-4679975.96478911,3640419.67074542, + 2050.0,-2331379.59681254,-4680030.50852172,3640507.47415395, + 2060.0,-2331132.08535529,-4680085.04396871,3640595.27111491, + 2070.0,-2330884.56978558,-4680139.57113,3640683.06162813, + 2080.0,-2330637.7285141,-4680190.9395453,3640774.43710409, + 2090.0,-2330396.40663506,-4680225.151778,3640884.18994119, + 2.1e3,-2330163.10529565,-4680238.35673454,3641015.64723137, + 2110.0,-2329932.54342047,-4680245.95830447,3641152.4979079, + 2120.0,-2329701.97743661,-4680253.55158212,3641289.34212236, + 2130.0,-2329471.40734447,-4680261.13656747,3641426.1798745, + 2140.0,-2329240.83314447,-4680268.71326052,3641563.01116407, + 2150.0,-2329010.25483703,-4680276.28166125,3641699.83599085, + 2160.0,-2328779.67242253,-4680283.84176964,3641836.65435457, + 2170.0,-2328549.08590139,-4680291.3935857,3641973.46625501, + 2180.0,-2328318.49527404,-4680298.9371094,3642110.27169193, + 2190.0,-2328087.90054086,-4680306.47234074,3642247.07066509, + 2.2e3,-2327857.30170227,-4680313.99927971,3642383.86317423, + 2210.0,-2327626.69875869,-4680321.51792628,3642520.64921913, + 2220.0,-2327396.09171053,-4680329.02828045,3642657.42879954, + 2230.0,-2327165.48055818,-4680336.53034222,3642794.20191522, + 2240.0,-2326934.86530206,-4680344.02411158,3642930.96856595, + 2250.0,-2326704.24594258,-4680351.50958849,3643067.72875145, + 2260.0,-2326473.62248015,-4680358.98677296,3643204.48247151, + 2270.0,-2326242.99491518,-4680366.45566498,3643341.22972587, + 2280.0,-2326012.36324808,-4680373.91626453,3643477.97051431, + 2290.0,-2325781.72747925,-4680381.36857161,3643614.70483658, + 2.3e3,-2325551.08760911,-4680388.8125862,3643751.43269243, + 2310.0,-2325320.44363806,-4680396.24830829,3643888.15408163, + 2320.0,-2325089.79556653,-4680403.67573787,3644024.86900394, + 2330.0,-2324859.14339491,-4680411.09487493,3644161.57745912, + 2340.0,-2324628.48712361,-4680418.50571946,3644298.27944692, + 2350.0,-2324397.82675305,-4680425.90827145,3644434.97496711, + 2360.0,-2324167.16228363,-4680433.30253088,3644571.66401943, + 2370.0,-2323936.49371575,-4680440.68849774,3644708.34660367, + 2380.0,-2323705.82104985,-4680448.06617203,3644845.02271957, + 2390.0,-2323469.56457492,-4680467.5014928,3644969.83533712, + 2.4e3,-2323221.0622471,-4680536.92026793,3645038.62868541, + 2410.0,-2322977.80807152,-4680647.84474283,3645051.13992706, + 2420.0,-2322736.38267079,-4680764.64879631,3645054.97445125, + 2430.0,-2322494.9531628,-4680881.44457147,3645058.80252916, + 2440.0,-2322246.73779559,-4680970.18567741,3645102.6916578, + 2450.0,-2322002.53536924,-4681011.67497706,3645204.29544116, + 2460.0,-2321760.17882828,-4681045.91276755,3645313.96140727, + 2470.0,-2321513.45780318,-4681097.83227119,3645403.81543108, + 2480.0,-2321264.12028187,-4681176.5278287,3645461.15182806, + 2490.0,-2321016.67956395,-4681275.07588805,3645491.94679701, + 2.5e3,-2320769.58665668,-4681375.58594799,3645519.99961511, + 2510.0,-2320522.489649,-4681476.08772649,3645548.04598517, + 2520.0,-2320275.38854134,-4681576.5812234,3645576.08590716, + 2530.0,-2320027.79132447,-4681674.92626117,3645607.16040563, + 2540.0,-2319780.10642819,-4681772.89945148,3645638.74505341, + 2550.0,-2319532.41743371,-4681870.86435933,3645670.32325269, + 2560.0,-2319284.72434146,-4681968.82098454,3645701.89500342, + 2570.0,-2319037.02715189,-4682066.76932694,3645733.46030553, + 2580.0,-2318789.32586542,-4682164.70938637,3645765.01915898, + 2590.0,-2318542.12778997,-4682264.83612099,3645793.45100625, + 2.6e3,-2318295.04606153,-4682365.47569326,3645821.1355313, + 2610.0,-2318047.960237,-4682466.10698239,3645848.81360781, + 2620.0,-2317814.2136072,-4682593.27748455,3645834.19098143, + 2630.0,-2317595.23970305,-4682740.17783799,3645785.0493345, + 2640.0,-2317367.51895524,-4682877.20966947,3645754.00173306, + 2650.0,-2317125.45200646,-4682991.24847734,3645761.32874791, + 2660.0,-2316877.25477931,-4683085.09280115,3645798.27256564, + 2670.0,-2316627.76750724,-4683171.42599527,3645845.59470414, + 2680.0,-2316378.41358519,-4683244.04371304,3645910.31301292, + 2690.0,-2316132.23045195,-4683290.83587254,3646005.96208532, + 2.7e3,-2315886.04323336,-4683337.61973972,3646101.60469867, + 2710.0,-2315639.85192986,-4683384.3953145,3646197.24085278, + 2720.0,-2315393.65654188,-4683431.1625968,3646292.8705475, + 2730.0,-2315147.45706986,-4683477.92158654,3646388.49378265, + 2740.0,-2314901.25351424,-4683524.67228364,3646484.11055807, + 2750.0,-2314655.04587545,-4683571.41468801,3646579.72087358, + 2760.0,-2314408.83415392,-4683618.14879957,3646675.32472902, + 2770.0,-2314160.70351457,-4683675.04338742,3646759.15642247, + 2780.0,-2313911.58484161,-4683762.87653752,3646804.12173857, + 2790.0,-2313665.46479966,-4683867.13714076,3646826.2202591, + 2.8e3,-2313419.44574948,-4683971.81359651,3646847.70500867, + 2810.0,-2313173.422611,-4684076.48176683,3646869.18330826, + 2820.0,-2312927.39538468,-4684181.14165156,3646890.65515782, + 2830.0,-2312681.36407094,-4684285.79325049,3646912.12055732, + 2840.0,-2312435.3286702,-4684390.43656345,3646933.57950672, + 2850.0,-2312188.68106177,-4684492.14732495,3646959.14603188, + 2860.0,-2311939.2573735,-4684576.69232926,3647008.34294359, + 2870.0,-2311690.53184969,-4684637.85664359,3647086.91208669, + 2880.0,-2311447.74208361,-4684672.93987918,3647195.00103929, + 2890.0,-2311210.79617263,-4684692.62730813,3647319.03447912, + 2.9e3,-2310974.46339778,-4684710.81501905,3647444.57574765, + 2910.0,-2310738.12654788,-4684728.99443131,3647570.11054652, + 2920.0,-2310501.78562334,-4684747.16554491,3647695.63887553, + 2930.0,-2310265.44062458,-4684765.3283598,3647821.16073445, + 2940.0,-2310029.09155203,-4684783.48287596,3647946.67612307, + 2950.0,-2309792.7384061,-4684801.62909336,3648072.18504115, + 2960.0,-2309556.38118721,-4684819.76701196,3648197.6874885, + 2970.0,-2309320.01989578,-4684837.89663174,3648323.18346488, + 2980.0,-2309083.65453223,-4684856.01795267,3648448.67297006, + 2990.0,-2308847.28509697,-4684874.13097471,3648574.15600382, + 3e3,-2308612.03960687,-4684889.78192809,3648702.05314508 + ] + } + } +] diff --git a/Apps/SampleData/MultipartVehicle_part3.czml b/Apps/SampleData/MultipartVehicle_part3.czml new file mode 100644 index 000000000000..610d6cb8ea15 --- /dev/null +++ b/Apps/SampleData/MultipartVehicle_part3.czml @@ -0,0 +1,114 @@ +[ + { + "id":"document", + "version":"1.0" + }, + { + "id":"Vehicle", + "properties" : { + "fuel_remaining" : { + "epoch":"2012-08-04T16:00:00Z", + "number": [ + 4500, 18.6 + ] + } + }, + "position":{ + "interpolationAlgorithm":"LAGRANGE", + "interpolationDegree":1, + "epoch":"2012-08-04T16:00:00Z", + "cartesian":[ + 3010.0,-2308376.92124893,-4684905.13917681,3648830.22535859, + 3020.0,-2308141.79882057,-4684920.48812622,3648958.39109918, + 3030.0,-2307906.6723222,-4684935.82877629,3649086.55036665, + 3040.0,-2307671.54175424,-4684951.161127,3649214.70316074, + 3050.0,-2307436.40711711,-4684966.48517831,3649342.84948124, + 3060.0,-2307201.26841123,-4684981.80093021,3649470.98932793, + 3070.0,-2306966.87575715,-4684995.59988061,3649600.57521538, + 3080.0,-2306740.26452813,-4684994.89962227,3649743.74372413, + 3090.0,-2306534.08725296,-4684964.25689728,3649912.24261594, + 3.1e3,-2306334.50436505,-4684925.31923873,3650087.15846994, + 3110.0,-2306134.91740775,-4684886.37327513,3650262.06783161, + 3120.0,-2305935.32638143,-4684847.41900655,3650436.97070063, + 3130.0,-2305735.73128644,-4684808.45643306,3650611.86707671, + 3140.0,-2305536.13212312,-4684769.48555472,3650786.75695952, + 3150.0,-2305336.52889186,-4684730.50637162,3650961.64034877, + 3160.0,-2305136.92159298,-4684691.51888382,3651136.51724414, + 3170.0,-2304937.31022685,-4684652.5230914,3651311.38764532, + 3180.0,-2304737.69479383,-4684613.51899443,3651486.25155201, + 3190.0,-2304538.07529427,-4684574.50659297,3651661.1089639, + 3.2e3,-2304338.45172854,-4684535.48588711,3651835.95988067, + 3210.0,-2304138.82409697,-4684496.45687691,3652010.80430203, + 3220.0,-2303939.19239993,-4684457.41956245,3652185.64222766, + 3230.0,-2303739.55663778,-4684418.37394379,3652360.47365726, + 3240.0,-2303539.91681086,-4684379.32002102,3652535.29859051, + 3250.0,-2303340.27291955,-4684340.25779419,3652710.11702711, + 3260.0,-2303140.62496419,-4684301.18726339,3652884.92896676, + 3270.0,-2302940.97294513,-4684262.10842868,3653059.73440913, + 3280.0,-2302741.31686273,-4684223.02129014,3653234.53335393, + 3290.0,-2302541.65671735,-4684183.92584784,3653409.32580085, + 3.3e3,-2302341.99250935,-4684144.82210185,3653584.11174957, + 3310.0,-2302142.32423908,-4684105.71005224,3653758.8911998, + 3320.0,-2301942.65190688,-4684066.5896991,3653933.66415121, + 3330.0,-2301742.97551314,-4684027.46104248,3654108.43060351, + 3340.0,-2301543.29505819,-4683988.32408245,3654283.19055638, + 3350.0,-2301343.61054239,-4683949.1788191,3654457.94400952, + 3360.0,-2301143.6827542,-4683910.31378064,3654632.47326169, + 3370.0,-2300935.59009252,-4683881.78114292,3654798.93579703, + 3380.0,-2300718.00641879,-4683866.2483759,3654954.7652541, + 3390.0,-2300494.16379595,-4683860.19477673,3655102.42228967, + 3.4e3,-2300270.31711639,-4683854.13287765,3655250.07283467, + 3410.0,-2300043.34951879,-4683853.58162531,3655392.64057225, + 3420.0,-2299798.57046824,-4683898.20991075,3655488.81767963, + 3430.0,-2299550.24237985,-4683986.73183877,3655531.32743747, + 3440.0,-2299302.19677383,-4684083.86163291,3655562.68543478, + 3450.0,-2299054.1471058,-4684180.98314055,3655594.03696606, + 3460.0,-2298806.09337623,-4684278.0963615,3655625.38203125, + 3470.0,-2298558.03558554,-4684375.2012956,3655656.7206303, + 3480.0,-2298309.97373417,-4684472.29794267,3655688.05276314, + 3490.0,-2298061.90782256,-4684569.38630254,3655719.37842974, + 3.5e3,-2297812.62950649,-4684659.16576897,3655760.74476938, + 3510.0,-2297564.67551281,-4684714.88851845,3655844.61445788, + 3520.0,-2297325.87128825,-4684739.27586645,3655962.6382433, + 3530.0,-2297109.10378606,-4684723.02803401,3656118.60908182, + 3540.0,-2296920.05504158,-4684672.53835408,3656300.84320686, + 3550.0,-2296752.93245501,-4684599.85791996,3656497.61758286, + 3560.0,-2296586.9421969,-4684526.13410832,3656694.99365465, + 3570.0,-2296420.94788222,-4684452.40199052,3656892.36321221, + 3580.0,-2296254.94951125,-4684378.66156669,3657089.72625519, + 3590.0,-2296088.9470843,-4684304.91283696,3657287.08278322, + 3.6e3,-2295922.94060166,-4684231.15580147,3657484.43279599, + 3610.0,-2295756.93006363,-4684157.39046036,3657681.77629313, + 3620.0,-2295590.91547051,-4684083.61681375,3657879.11327429, + 3630.0,-2295424.89682259,-4684009.83486178,3658076.44373913, + 3640.0,-2295258.87412016,-4683936.04460459,3658273.7676873, + 3650.0,-2295092.84736354,-4683862.24604231,3658471.08511845, + 3660.0,-2294926.816553,-4683788.43917507,3658668.39603222, + 3670.0,-2294760.78168886,-4683714.62400301,3658865.70042829, + 3680.0,-2294594.74277139,-4683640.80052626,3659062.99830628, + 3690.0,-2294428.69980091,-4683566.96874495,3659260.28966586, + 3.7e3,-2294262.65277771,-4683493.12865923,3659457.57450667, + 3710.0,-2294096.43623008,-4683419.42772878,3659654.7684149, + 3720.0,-2293929.99691308,-4683345.91340302,3659851.84422781, + 3730.0,-2293763.5535443,-4683272.39077326,3660048.91352102, + 3740.0,-2293597.10612405,-4683198.85983962,3660245.97629416, + 3750.0,-2293430.65465261,-4683125.32060225,3660443.03254689, + 3760.0,-2293260.27703319,-4683055.37159052,3660637.95010862, + 3770.0,-2293061.03795256,-4683015.37278429,3660812.74893793, + 3780.0,-2292840.33611906,-4683005.33804065,3660962.80786551, + 3790.0,-2292608.06534954,-4683013.68106842,3661096.69339637, + 3.8e3,-2292375.79053761,-4683022.01579957,3661230.57243073, + 3810.0,-2292143.51168366,-4683030.3422341,3661364.44496835, + 3820.0,-2291911.22878812,-4683038.66037197,3661498.311009, + 3830.0,-2291675.19260926,-4683056.38281492,3661622.54366342, + 3840.0,-2291444.11976688,-4683176.79169794,3661613.21949622, + 3850.0,-2291484.73184242,-4683029.11180042,3661775.58481802, + 3860.0,-2291570.38402198,-4682848.00432402,3661952.40110212, + 3870.0,-2291504.75912943,-4682707.90868127,3662171.13586741, + 3880.0,-2291437.4576409,-4682568.41526623,3662390.12822003, + 3890.0,-2291370.1520906,-4682428.91355119,3662609.11403735, + 3894.996219574019,-2291336.52323822,-4682359.21232197,3662718.52171165 + ] + } + } +] diff --git a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html index ca5698c3faa5..df2f4e429d3e 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html +++ b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html @@ -48,7 +48,6 @@ // Add a clipping plane, a plane geometry to show the representation of the // plane, and control the magnitude of the plane distance with the mouse. -// Clipping planes are not currently supported in Internet Explorer. var viewer = new Cesium.Viewer('cesiumContainer', { infoBox: false, @@ -103,7 +102,7 @@ } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); -var scratchPlane = new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0.0); +var scratchPlane = new Cesium.ClippingPlane(Cesium.Cartesian3.UNIT_X, 0.0); function createPlaneUpdateFunction(plane, transform) { return function () { plane.distance = targetY; @@ -114,7 +113,7 @@ var tileset; function loadTileset(url) { var clippingPlanes = [ - new Cesium.Plane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) + new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) ]; tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ @@ -156,7 +155,7 @@ var modelEntityClippingPlanes; function loadModel(url) { var clippingPlanes = [ - new Cesium.Plane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) + new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) ]; modelEntityClippingPlanes = new Cesium.ClippingPlaneCollection({ diff --git a/Apps/Sandcastle/gallery/Multi-part CZML.html b/Apps/Sandcastle/gallery/Multi-part CZML.html new file mode 100644 index 000000000000..68b80c6b1fa2 --- /dev/null +++ b/Apps/Sandcastle/gallery/Multi-part CZML.html @@ -0,0 +1,158 @@ + + +
+ + + + + +Distance | ++ + + | +Plane Count | ++ + + | +
distance
determines which side of the plane the origin
+ * is on. If distance
is positive, the origin is in the half-space
+ * in the direction of the normal; if negative, the origin is in the half-space
+ * opposite to the normal; if zero, the plane passes through the origin.
+ */
+ function ClippingPlane(normal, distance) {
+ this._distance = distance;
+ this._normal = new UpdateChangedCartesian3(normal, this);
+ this.onChangeCallback = undefined;
+ this.index = -1; // to be set by ClippingPlaneCollection
+ }
+
+ defineProperties(ClippingPlane.prototype, {
+ /**
+ * The shortest distance from the origin to the plane. The sign of
+ * distance
determines which side of the plane the origin
+ * is on. If distance
is positive, the origin is in the half-space
+ * in the direction of the normal; if negative, the origin is in the half-space
+ * opposite to the normal; if zero, the plane passes through the origin.
+ *
+ * @type {Number}
+ * @memberof ClippingPlane.prototype
+ */
+ distance : {
+ get : function() {
+ return this._distance;
+ },
+ set : function(value) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number('value', value);
+ //>>includeEnd('debug');
+ if (defined(this.onChangeCallback) && value !== this._distance) {
+ this.onChangeCallback(this.index);
+ }
+ this._distance = value;
+ }
+ },
+ /**
+ * The plane's normal.
+ *
+ * @type {Cartesian3}
+ * @memberof ClippingPlane.prototype
+ */
+ normal : {
+ get : function() {
+ return this._normal;
+ },
+ set : function(value) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object('value', value);
+ //>>includeEnd('debug');
+ if (defined(this.onChangeCallback) && !Cartesian3.equals(this._normal._cartesian3, value)) {
+ this.onChangeCallback(this.index);
+ }
+ // Set without firing callback again
+ Cartesian3.clone(value, this._normal._cartesian3);
+ }
+ }
+ });
+
+ /**
+ * Create a ClippingPlane from a Plane object.
+ *
+ * @param {Plane} plane The plane containing parameters to copy
+ * @param {ClippingPlane} [result] The object on which to store the result
+ * @returns {ClippingPlane} The ClippingPlane generated from the plane's parameters.
+ */
+ ClippingPlane.fromPlane = function(plane, result) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object('plane', plane);
+ //>>includeEnd('debug');
+
+ if (!defined(result)) {
+ result = new ClippingPlane(plane.normal, plane.distance);
+ } else {
+ result.normal = plane.normal;
+ result.distance = plane.distance;
+ }
+ return result;
+ };
+
+ /**
+ * Clones the ClippingPlane without setting its ownership.
+ * @param {ClippingPlane} clippingPlane The ClippingPlane to be cloned
+ * @param {ClippingPlane} [result] The object on which to store the cloned parameters.
+ * @returns {ClippingPlane} a clone of the input ClippingPlane
+ */
+ ClippingPlane.clone = function(clippingPlane, result) {
+ if (!defined(result)) {
+ return new ClippingPlane(clippingPlane.normal, clippingPlane.distance);
+ }
+ result.normal = clippingPlane.normal;
+ result.distance = clippingPlane.distance;
+ return result;
+ };
+
+ /**
+ * Wrapper on Cartesian3 that allows detection of Plane changes from "members of members," for example:
+ *
+ * var clippingPlane = new ClippingPlane(...);
+ * clippingPlane.normal.z = -1.0;
+ *
+ * @private
+ */
+ function UpdateChangedCartesian3(normal, clippingPlane) {
+ this._clippingPlane = clippingPlane;
+ this._cartesian3 = Cartesian3.clone(normal);
+ }
+
+ function makeGetterStter(key) {
+ return {
+ get : function() {
+ return this._cartesian3[key];
+ },
+ set : function(value) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.number('value', value);
+ //>>includeEnd('debug');
+ if (defined(this._clippingPlane.onChangeCallback) && value !== this._cartesian3[key]) {
+ this._clippingPlane.onChangeCallback(this._clippingPlane.index);
+ }
+ this._cartesian3[key] = value;
+ }
+ };
+ }
+
+ defineProperties(UpdateChangedCartesian3.prototype, {
+ x : makeGetterStter('x'),
+ y : makeGetterStter('y'),
+ z : makeGetterStter('z')
+ });
+
+ return ClippingPlane;
+});
diff --git a/Source/Core/ClippingPlaneCollection.js b/Source/Core/ClippingPlaneCollection.js
index 56369d69202f..b1ca230c41d8 100644
--- a/Source/Core/ClippingPlaneCollection.js
+++ b/Source/Core/ClippingPlaneCollection.js
@@ -1,40 +1,68 @@
define([
+ './AttributeCompression',
+ './Cartesian2',
'./Cartesian3',
'./Cartesian4',
+ './Math',
'./Check',
+ './ClippingPlane',
'./Color',
'./defaultValue',
'./defined',
'./defineProperties',
+ './deprecationWarning',
+ './destroyObject',
'./DeveloperError',
'./FeatureDetection',
'./Intersect',
'./Matrix4',
- './Plane'
+ './PixelFormat',
+ './Plane',
+ '../Renderer/ContextLimits',
+ '../Renderer/PixelDatatype',
+ '../Renderer/Sampler',
+ '../Renderer/Texture',
+ '../Renderer/TextureMagnificationFilter',
+ '../Renderer/TextureMinificationFilter',
+ '../Renderer/TextureWrap'
], function(
+ AttributeCompression,
+ Cartesian2,
Cartesian3,
Cartesian4,
+ CesiumMath,
Check,
+ ClippingPlane,
Color,
defaultValue,
defined,
defineProperties,
+ deprecationWarning,
+ destroyObject,
DeveloperError,
FeatureDetection,
Intersect,
Matrix4,
- Plane) {
+ PixelFormat,
+ Plane,
+ ContextLimits,
+ PixelDatatype,
+ Sampler,
+ Texture,
+ TextureMagnificationFilter,
+ TextureMinificationFilter,
+ TextureWrap) {
'use strict';
/**
* Specifies a set of clipping planes. Clipping planes selectively disable rendering in a region on the
- * outside of the specified list of {@link Plane} objects.
+ * outside of the specified list of {@link ClippingPlane} objects for a single gltf model, 3D Tileset, or the globe.
*
* @alias ClippingPlaneCollection
* @constructor
*
* @param {Object} [options] Object with the following properties:
- * @param {Plane[]} [options.planes=[]] An array of up to 6 {@link Plane} objects used to selectively disable rendering on the outside of each plane.
+ * @param {ClippingPlane[]} [options.planes=[]] An array of {@link ClippingPlane} objects used to selectively disable rendering on the outside of each plane.
* @param {Boolean} [options.enabled=true] Determines whether the clipping planes are active.
* @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix specifying an additional transform relative to the clipping planes original coordinate system.
* @param {Boolean} [options.unionClippingRegions=false] If true, a region will be clipped if included in any plane in the collection. Otherwise, the region to be clipped must intersect the regions defined by all planes in this collection.
@@ -44,20 +72,26 @@ define([
function ClippingPlaneCollection(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ this._planes = [];
+ this._containsUntrackablePlanes = false;
+
+ // Do partial texture updates if just one plane is dirty.
+ // If many planes are dirty, refresh the entire texture.
+ this._dirtyIndex = -1;
+ this._manyDirtyPlanes = false;
+
+ // Add each plane to check if it's actually a Plane object instead of a ClippingPlane.
+ // Use of Plane objects will be deprecated.
var planes = options.planes;
if (defined(planes)) {
- this._planes = planes.slice(0);
- } else {
- this._planes = [];
+ var planesLength = planes.length;
+ for (var i = 0; i < planesLength; ++i) {
+ this.add(planes[i]);
+ }
}
- /**
- * Determines whether the clipping planes are active.
- *
- * @type {Boolean}
- * @default true
- */
- this.enabled = defaultValue(options.enabled, true);
+ this._enabled = false;
+ this.enabled = defaultValue(options.enabled, true); // set using setter
/**
* The 4x4 transformation matrix specifying an additional transform relative to the clipping planes
@@ -84,9 +118,18 @@ define([
*/
this.edgeWidth = defaultValue(options.edgeWidth, 0.0);
+ // If this ClippingPlaneCollection has an owner, only its owner should update or destroy it.
+ // This is because in a Cesium3DTileset multiple models may reference the tileset's ClippingPlaneCollection.
+ this._owner = undefined;
+
this._testIntersection = undefined;
this._unionClippingRegions = undefined;
- this.unionClippingRegions = defaultValue(options.unionClippingRegions, false);
+ this.unionClippingRegions = defaultValue(options.unionClippingRegions, false); // set using setter
+
+ this._uint8View = undefined;
+ this._float32View = undefined;
+
+ this._clippingPlanesTexture = undefined;
}
function unionIntersectFunction(value) {
@@ -126,34 +169,92 @@ define([
return this._unionClippingRegions;
},
set : function(value) {
- if (this._unionClippingRegions !== value) {
- this._unionClippingRegions = value;
- this._testIntersection = value ? unionIntersectFunction : defaultIntersectFunction;
+ if (this._unionClippingRegions === value) {
+ return;
}
+ this._unionClippingRegions = value;
+ this._testIntersection = value ? unionIntersectFunction : defaultIntersectFunction;
+ }
+ },
+
+ /**
+ * If true, clipping will be enabled.
+ *
+ * @memberof ClippingPlaneCollection.prototype
+ * @type {Boolean}
+ * @default false
+ */
+ enabled : {
+ get : function() {
+ return this._enabled;
+ },
+ set : function(value) {
+ if (this._enabled === value) {
+ return;
+ }
+ this._enabled = value;
+ }
+ },
+
+ /**
+ * Returns a texture containing packed, untransformed clipping planes.
+ *
+ * @memberof ClippingPlaneCollection.prototype
+ * @type {Texture}
+ * @readonly
+ * @private
+ */
+ texture : {
+ get : function() {
+ return this._clippingPlanesTexture;
+ }
+ },
+
+ /**
+ * A reference to the ClippingPlaneCollection's owner, if any.
+ *
+ * @memberof ClippingPlaneCollection.prototype
+ * @readonly
+ * @private
+ */
+ owner : {
+ get : function() {
+ return this._owner;
}
}
});
+ function setIndexDirty(collection, index) {
+ // If there's already a different _dirtyIndex set, more than one plane has changed since update.
+ // Entire texture must be reloaded
+ collection._manyDirtyPlanes = collection._manyDirtyPlanes || (collection._dirtyIndex !== -1 && collection._dirtyIndex !== index);
+ collection._dirtyIndex = index;
+ }
+
/**
- * Adds the specified {@link Plane} to the collection to be used to selectively disable rendering
+ * Adds the specified {@link ClippingPlane} to the collection to be used to selectively disable rendering
* on the outside of each plane. Use {@link ClippingPlaneCollection#unionClippingRegions} to modify
* how modify the clipping behavior of multiple planes.
*
- * @param {Plane} plane The plane to add to the collection.
- *
- * @exception {DeveloperError} The plane added exceeds the maximum number of supported clipping planes.
+ * @param {ClippingPlane} plane The ClippingPlane to add to the collection.
*
* @see ClippingPlaneCollection#unionClippingRegions
* @see ClippingPlaneCollection#remove
* @see ClippingPlaneCollection#removeAll
*/
ClippingPlaneCollection.prototype.add = function(plane) {
- //>>includeStart('debug', pragmas.debug);
- if (this.length >= ClippingPlaneCollection.MAX_CLIPPING_PLANES) {
- throw new DeveloperError('The maximum number of clipping planes supported is ' + ClippingPlaneCollection.MAX_CLIPPING_PLANES);
+ var newPlaneIndex = this._planes.length;
+ if (plane instanceof ClippingPlane) {
+ var that = this;
+ plane.onChangeCallback = function(index) {
+ setIndexDirty(that, index);
+ };
+ plane.index = newPlaneIndex;
+ } else {
+ deprecationWarning('ClippingPlaneCollection.add', 'Ability to use Plane objects with ClippingPlaneCollection.add is deprecated and will be removed in Cesium 1.45. Please use ClippingPlane objects instead.');
+ this._containsUntrackablePlanes = true;
}
- //>>includeEnd('debug');
-
+ setIndexDirty(this, newPlaneIndex);
this._planes.push(plane);
};
@@ -165,7 +266,7 @@ define([
* in the collection.
*
* @param {Number} index The zero-based index of the plane.
- * @returns {Plane} The plane at the specified index.
+ * @returns {ClippingPlane} The ClippingPlane at the specified index.
*
* @see ClippingPlaneCollection#length
*/
@@ -189,39 +290,53 @@ define([
}
/**
- * Checks whether this collection contains the given plane.
+ * Checks whether this collection contains a ClippingPlane equal to the given ClippingPlane.
*
- * @param {Plane} [plane] The plane to check for.
- * @returns {Boolean} true if this collection contains the plane, false otherwise.
+ * @param {ClippingPlane} [clippingPlane] The ClippingPlane to check for.
+ * @returns {Boolean} true if this collection contains the ClippingPlane, false otherwise.
*
* @see ClippingPlaneCollection#get
*/
- ClippingPlaneCollection.prototype.contains = function(plane) {
- return indexOf(this._planes, plane) !== -1;
+ ClippingPlaneCollection.prototype.contains = function(clippingPlane) {
+ return indexOf(this._planes, clippingPlane) !== -1;
};
/**
- * Removes the first occurrence of the given plane from the collection.
+ * Removes the first occurrence of the given ClippingPlane from the collection.
*
- * @param {Plane} plane
+ * @param {ClippingPlane} clippingPlane
* @returns {Boolean} true
if the plane was removed; false
if the plane was not found in the collection.
*
* @see ClippingPlaneCollection#add
* @see ClippingPlaneCollection#contains
* @see ClippingPlaneCollection#removeAll
*/
- ClippingPlaneCollection.prototype.remove = function(plane) {
+ ClippingPlaneCollection.prototype.remove = function(clippingPlane) {
var planes = this._planes;
- var index = indexOf(planes, plane);
+ var index = indexOf(planes, clippingPlane);
if (index === -1) {
return false;
}
+ // Unlink this ClippingPlaneCollection from the ClippingPlane
+ if (clippingPlane instanceof ClippingPlane) {
+ clippingPlane.onChangeCallback = undefined;
+ clippingPlane.index = -1;
+ }
+
+ // Shift and update indices
var length = planes.length - 1;
for (var i = index; i < length; ++i) {
- planes[i] = planes[i + 1];
+ var planeToKeep = planes[i + 1];
+ planes[i] = planeToKeep;
+ if (planeToKeep instanceof ClippingPlane) {
+ planeToKeep.index = i;
+ }
}
+
+ // Indicate planes texture is dirty
+ this._manyDirtyPlanes = true;
planes.length = length;
return true;
@@ -234,53 +349,203 @@ define([
* @see ClippingPlaneCollection#remove
*/
ClippingPlaneCollection.prototype.removeAll = function() {
+ // Dereference this ClippingPlaneCollection from all ClippingPlanes
+ var planes = this._planes;
+ var planesCount = planes.length;
+ for (var i = 0; i < planesCount; ++i) {
+ var plane = planes[i];
+ if (plane instanceof ClippingPlane) {
+ plane.onChangeCallback = undefined;
+ plane.index = -1;
+ }
+ }
+ this._manyDirtyPlanes = true;
this._planes = [];
};
- var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0);
- var scratchMatrix = new Matrix4();
+ var octEncodeScratch = new Cartesian2();
+ var rightShift = 1.0 / 256.0;
/**
- * Applies the transformations to each plane and packs it into an array.
- * @private
- *
- * @param {Matrix4} viewMatrix The 4x4 matrix to transform the plane into eyespace.
- * @param {Cartesian4[]} [array] The array into which the planes will be packed.
- * @returns {Cartesian4[]} The array of packed planes.
+ * Encodes a normalized vector into 4 SNORM values in the range [0-255] following the 'oct' encoding.
+ * oct32 precision is higher than the default oct16, hence the additional 2 uint16 values.
*/
- ClippingPlaneCollection.prototype.transformAndPackPlanes = function(viewMatrix, array) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object('viewMatrix', viewMatrix);
- //>>includeEnd('debug');
+ function oct32EncodeNormal(vector, result) {
+ AttributeCompression.octEncodeInRange(vector, 65535, octEncodeScratch);
+ result.x = octEncodeScratch.x * rightShift;
+ result.y = octEncodeScratch.x;
+ result.z = octEncodeScratch.y * rightShift;
+ result.w = octEncodeScratch.y;
+ return result;
+ }
- var planes = this._planes;
- var length = planes.length;
+ var distanceEncodeScratch = new Cartesian4();
+ var oct32EncodeScratch = new Cartesian4();
+ function packPlanesAsUint8(clippingPlaneCollection, startIndex, endIndex) {
+ var uint8View = clippingPlaneCollection._uint8View;
+ var planes = clippingPlaneCollection._planes;
+ var byteIndex = 0;
+ for (var i = startIndex; i < endIndex; ++i) {
+ var plane = planes[i];
- var index = 0;
- if (!defined(array)) {
- array = new Array(length);
- } else {
- index = array.length;
- array.length = length;
- }
+ var oct32Normal = oct32EncodeNormal(plane.normal, oct32EncodeScratch);
+ uint8View[byteIndex] = oct32Normal.x;
+ uint8View[byteIndex + 1] = oct32Normal.y;
+ uint8View[byteIndex + 2] = oct32Normal.z;
+ uint8View[byteIndex + 3] = oct32Normal.w;
- var i;
- for (i = index; i < length; ++i) {
- array[i] = new Cartesian4();
+ var encodedDistance = Cartesian4.packFloat(plane.distance, distanceEncodeScratch);
+ uint8View[byteIndex + 4] = encodedDistance.x;
+ uint8View[byteIndex + 5] = encodedDistance.y;
+ uint8View[byteIndex + 6] = encodedDistance.z;
+ uint8View[byteIndex + 7] = encodedDistance.w;
+
+ byteIndex += 8;
}
+ }
- var transform = Matrix4.multiply(viewMatrix, this.modelMatrix, scratchMatrix);
+ // Pack starting at the beginning of the buffer to allow partial update
+ function packPlanesAsFloats(clippingPlaneCollection, startIndex, endIndex) {
+ var float32View = clippingPlaneCollection._float32View;
+ var planes = clippingPlaneCollection._planes;
- for (i = 0; i < length; ++i) {
+ var floatIndex = 0;
+ for (var i = startIndex; i < endIndex; ++i) {
var plane = planes[i];
- var packedPlane = array[i];
+ var normal = plane.normal;
- Plane.transform(plane, transform, scratchPlane);
+ float32View[floatIndex] = normal.x;
+ float32View[floatIndex + 1] = normal.y;
+ float32View[floatIndex + 2] = normal.z;
+ float32View[floatIndex + 3] = plane.distance;
- Cartesian3.clone(scratchPlane.normal, packedPlane);
- packedPlane.w = scratchPlane.distance;
+ floatIndex += 4; // each plane is 4 floats
}
+ }
+
+ function computeTextureResolution(pixelsNeeded, result) {
+ var maxSize = ContextLimits.maximumTextureSize;
+ var width = Math.min(pixelsNeeded, maxSize);
+ var height = Math.ceil(pixelsNeeded / width);
+ result.x = width;
+ result.y = height;
+ return result;
+ }
- return array;
+ var textureResolutionScratch = new Cartesian2();
+ /**
+ * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
+ * build the resources for clipping planes.
+ * + * Do not call this function directly. + *
+ */ + ClippingPlaneCollection.prototype.update = function(frameState) { + var clippingPlanesTexture = this._clippingPlanesTexture; + var context = frameState.context; + var useFloatTexture = ClippingPlaneCollection.useFloatTexture(context); + + // Compute texture requirements for current planes + // In RGBA FLOAT, A plane is 4 floats packed to a RGBA. + // In RGBA UNSIGNED_BYTE, A plane is a float in [0, 1) packed to RGBA and an Oct32 quantized normal, + // so 8 bits or 2 pixels in RGBA. + var pixelsNeeded = useFloatTexture ? this.length : this.length * 2; + var requiredResolution = computeTextureResolution(pixelsNeeded, textureResolutionScratch); + + if (defined(clippingPlanesTexture)) { + var currentPixelCount = clippingPlanesTexture.width * clippingPlanesTexture.height; + // Recreate the texture if it isn't big enough or is 4 times larger than it needs to be + if (currentPixelCount < pixelsNeeded || + pixelsNeeded < 0.25 * currentPixelCount) { + clippingPlanesTexture.destroy(); + clippingPlanesTexture = undefined; + } + } + + if (!defined(clippingPlanesTexture)) { + // Allocate twice as much space as needed to avoid frequent texture reallocation. + requiredResolution.x *= 2; + + var sampler = new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.NEAREST, + magnificationFilter : TextureMagnificationFilter.NEAREST + }); + + if (useFloatTexture) { + clippingPlanesTexture = new Texture({ + context : context, + width : requiredResolution.x, + height : requiredResolution.y, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.FLOAT, + sampler : sampler, + flipY : false + }); + this._float32View = new Float32Array(requiredResolution.x * requiredResolution.y * 4); + } else { + clippingPlanesTexture = new Texture({ + context : context, + width : requiredResolution.x, + height : requiredResolution.y, + pixelFormat : PixelFormat.RGBA, + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : sampler, + flipY : false + }); + this._uint8View = new Uint8Array(requiredResolution.x * requiredResolution.y * 4); + } + + this._clippingPlanesTexture = clippingPlanesTexture; + this._manyDirtyPlanes = true; + } + + // Use of Plane objects will be deprecated. + // But until then, we have no way of telling if they changed since last frame, so we have to do a full udpate. + var refreshFullTexture = this._manyDirtyPlanes || this._containsUntrackablePlanes; + var dirtyIndex = this._dirtyIndex; + + if (!refreshFullTexture && dirtyIndex === -1) { + return; + } + + if (!refreshFullTexture) { + // partial updates possible + var offsetY = Math.floor(dirtyIndex / clippingPlanesTexture.width); + var offsetX = Math.floor(dirtyIndex - offsetY * clippingPlanesTexture.width); + if (useFloatTexture) { + packPlanesAsFloats(this, dirtyIndex, dirtyIndex + 1); + clippingPlanesTexture.copyFrom({ + width : 1, + height : 1, + arrayBufferView : this._float32View + }, offsetX, offsetY); + } else { + packPlanesAsUint8(this, dirtyIndex, dirtyIndex + 1); + clippingPlanesTexture.copyFrom({ + width : 2, + height : 1, + arrayBufferView : this._uint8View + }, offsetX, offsetY); + } + } else if (useFloatTexture) { + packPlanesAsFloats(this, 0, this._planes.length); + clippingPlanesTexture.copyFrom({ + width : clippingPlanesTexture.width, + height : clippingPlanesTexture.height, + arrayBufferView : this._float32View + }); + } else { + packPlanesAsUint8(this, 0, this._planes.length); + clippingPlanesTexture.copyFrom({ + width : clippingPlanesTexture.width, + height : clippingPlanesTexture.height, + arrayBufferView : this._uint8View + }); + } + + this._manyDirtyPlanes = false; + this._dirtyIndex = -1; }; /** @@ -302,12 +567,17 @@ define([ planes.length = length; for (i = index; i < length; ++i) { - result._planes[i] = new Plane(Cartesian3.UNIT_X, 0.0); + result._planes[i] = new ClippingPlane(Cartesian3.UNIT_X, 0.0); } } for (i = 0; i < length; ++i) { - Plane.clone(this._planes[i], result._planes[i]); + var resultPlane = result._planes[i]; + resultPlane.index = i; + resultPlane.onChangeCallback = function(index) { + setIndexDirty(result, index); + }; + ClippingPlane.clone(this._planes[i], resultPlane); } result.enabled = this.enabled; @@ -319,18 +589,20 @@ define([ return result; }; + var scratchMatrix = new Matrix4(); + var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0); /** - * Determines the type intersection with the planes of this ClippingPlaneCollection instance and the specified {@link BoundingVolume}. + * Determines the type intersection with the planes of this ClippingPlaneCollection instance and the specified {@link TileBoundingVolume}. * @private * - * @param {Object} boundingVolume The volume to determine the intersection with the planes. + * @param {Object} tileBoundingVolume The volume to determine the intersection with the planes. * @param {Matrix4} [transform] An optional, additional matrix to transform the plane to world coordinates. * @returns {Intersect} {@link Intersect.INSIDE} if the entire volume is on the side of the planes * the normal is pointing and should be entirely rendered, {@link Intersect.OUTSIDE} * if the entire volume is on the opposite side and should be clipped, and * {@link Intersect.INTERSECTING} if the volume intersects the planes. */ - ClippingPlaneCollection.prototype.computeIntersectionWithBoundingVolume = function(boundingVolume, transform) { + ClippingPlaneCollection.prototype.computeIntersectionWithBoundingVolume = function(tileBoundingVolume, transform) { var planes = this._planes; var length = planes.length; @@ -351,9 +623,9 @@ define([ for (var i = 0; i < length; ++i) { var plane = planes[i]; - Plane.transform(plane, modelMatrix, scratchPlane); + Plane.transform(plane, modelMatrix, scratchPlane); // ClippingPlane can be used for Plane math - var value = boundingVolume.intersectPlane(scratchPlane); + var value = tileBoundingVolume.intersectPlane(scratchPlane); if (value === Intersect.INTERSECTING) { intersection = value; } else if (this._testIntersection(value)) { @@ -364,22 +636,104 @@ define([ return intersection; }; + /** + * Returns a Number encapsulating the state for this ClippingPlaneCollection. + * + * Clipping mode is encoded in the sign of the number, which is just the plane count. + * Used for checking if shader regeneration is necessary. + * + * @returns {Number} A Number that describes the ClippingPlaneCollection's state. + * @private + */ + ClippingPlaneCollection.prototype.clippingPlanesState = function() { + return this._unionClippingRegions ? this._planes.length : -this._planes.length; + }; + + /** + * Sets the owner for the input ClippingPlaneCollection if there wasn't another owner. + * Destroys the owner's previous ClippingPlaneCollection if setting is successful. + * + * @param {ClippingPlaneCollection} [clippingPlaneCollection] A ClippingPlaneCollection (or undefined) being attached to an object + * @param {Object} owner An Object that should receive the new ClippingPlaneCollection + * @param {String} key The Key for the Object to reference the ClippingPlaneCollection + * @private + */ + ClippingPlaneCollection.setOwnership = function(clippingPlaneCollection, owner, key) { + // Don't destroy the ClippingPlaneCollection if it is already owned by newOwner + if (clippingPlaneCollection === owner[key]) { + return; + } + // Destroy the existing ClippingPlaneCollection, if any + owner[key] = owner[key] && owner[key].destroy(); + if (defined(clippingPlaneCollection)) { + //>>includeStart('debug', pragmas.debug); + if (defined(clippingPlaneCollection._owner)) { + throw new DeveloperError('ClippingPlaneCollection should only be assigned to one object'); + } + //>>includeEnd('debug'); + clippingPlaneCollection._owner = owner; + owner[key] = clippingPlaneCollection; + } + }; + /** * Determines if rendering with clipping planes is supported. * - * @returns {Boolean}true
if ClippingPlaneCollections are supported; otherwise, returns false
+ * @returns {Boolean} true
if ClippingPlaneCollections are supported
+ * @deprecated
*/
ClippingPlaneCollection.isSupported = function() {
- return !FeatureDetection.isInternetExplorer();
+ deprecationWarning('ClippingPlaneCollection.isSupported', 'ClippingPlaneCollection.isSupported is deprecated and will be removed in Cesium 1.45. Clipping Planes are now supported on all platforms capable of running Cesium.');
+ return true;
+ };
+
+ /**
+ * Function for checking if the context will allow clipping planes with floating point textures.
+ *
+ * @param {Context} context The Context that will contain clipped objects and clipping textures.
+ * @returns {Boolean} true
if floating point textures can be used for clipping planes.
+ * @private
+ */
+ ClippingPlaneCollection.useFloatTexture = function(context) {
+ return context.floatingPointTexture;
+ };
+
+ /**
+ * Returns true if this object was destroyed; otherwise, false.
+ * isDestroyed
will result in a {@link DeveloperError} exception.
+ *
+ * @returns {Boolean} true
if this object was destroyed; otherwise, false
.
+ *
+ * @see ClippingPlaneCollection#destroy
+ */
+ ClippingPlaneCollection.prototype.isDestroyed = function() {
+ return false;
};
/**
- * The maximum number of supported clipping planes.
+ * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
+ * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
+ * isDestroyed
will result in a {@link DeveloperError} exception. Therefore,
+ * assign the return value (undefined
) to the object as done in the example.
+ *
+ * @returns {undefined}
*
- * @type {number}
- * @constant
+ * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
+ *
+ *
+ * @example
+ * clippingPlanes = clippingPlanes && clippingPlanes .destroy();
+ *
+ * @see ClippingPlaneCollection#isDestroyed
*/
- ClippingPlaneCollection.MAX_CLIPPING_PLANES = 6;
+ ClippingPlaneCollection.prototype.destroy = function() {
+ this._clippingPlanesTexture = this._clippingPlanesTexture && this._clippingPlanesTexture.destroy();
+ return destroyObject(this);
+ };
return ClippingPlaneCollection;
});
diff --git a/Source/DataSources/ModelGraphics.js b/Source/DataSources/ModelGraphics.js
index 5dedd97c6f94..1b6c77f82b32 100644
--- a/Source/DataSources/ModelGraphics.js
+++ b/Source/DataSources/ModelGraphics.js
@@ -55,7 +55,7 @@ define([
* @param {Property} [options.color=Color.WHITE] A Property specifying the {@link Color} that blends with the model's rendered color.
* @param {Property} [options.colorBlendMode=ColorBlendMode.HIGHLIGHT] An enum Property specifying how the color blends with the model.
* @param {Property} [options.colorBlendAmount=0.5] A numeric Property specifying the color strength when the colorBlendMode
is MIX
. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
- * @param {Property} [options.clippingPlanes] A property specifying the {@link ClippingPlaneCollection} used to selectively disable rendering the model. Clipping planes are not currently supported in Internet Explorer.
+ * @param {Property} [options.clippingPlanes] A property specifying the {@link ClippingPlaneCollection} used to selectively disable rendering the model.
*
* @see {@link https://cesiumjs.org/tutorials/3D-Models-Tutorial/|3D Models Tutorial}
* @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=3D%20Models.html|Cesium Sandcastle 3D Models Demo}
diff --git a/Source/DataSources/ModelVisualizer.js b/Source/DataSources/ModelVisualizer.js
index 68779e161e51..37954219c7a2 100644
--- a/Source/DataSources/ModelVisualizer.js
+++ b/Source/DataSources/ModelVisualizer.js
@@ -126,9 +126,6 @@ define([
incrementallyLoadTextures : Property.getValueOrDefault(modelGraphics._incrementallyLoadTextures, time, defaultIncrementallyLoadTextures),
scene : this._scene
});
-
- model.readyPromise.otherwise(onModelError);
-
model.id = entity;
primitives.add(model);
@@ -137,9 +134,12 @@ define([
url : resource.url,
animationsRunning : false,
nodeTransformationsScratch : {},
- originalNodeMatrixHash : {}
+ originalNodeMatrixHash : {},
+ loadFail : false
};
modelHash[entity.id] = modelData;
+
+ checkModelLoad(model, entity, modelHash);
}
model.show = true;
@@ -250,7 +250,7 @@ define([
//>>includeEnd('debug');
var modelData = this._modelHash[entity.id];
- if (!defined(modelData)) {
+ if (!defined(modelData) || modelData.loadFail) {
return BoundingSphereState.FAILED;
}
@@ -324,8 +324,11 @@ define([
}
}
- function onModelError(error) {
- console.error(error);
+ function checkModelLoad(model, entity, modelHash){
+ model.readyPromise.otherwise(function(error){
+ console.error(error);
+ modelHash[entity.id].loadFail = true;
+ });
}
return ModelVisualizer;
diff --git a/Source/Renderer/AutomaticUniforms.js b/Source/Renderer/AutomaticUniforms.js
index 82c0b64ad9fd..1556c5b2ad9c 100644
--- a/Source/Renderer/AutomaticUniforms.js
+++ b/Source/Renderer/AutomaticUniforms.js
@@ -912,6 +912,20 @@ define([
}
}),
+ /**
+ * An automatic GLSL uniform that indicates if the current camera is orthographic in 3D.
+ *
+ * @alias czm_orthographicIn3D
+ * @see UniformState#orthographicIn3D
+ */
+ czm_orthographicIn3D : new AutomaticUniform({
+ size : 1,
+ datatype : WebGLConstants.FLOAT,
+ getValue : function(uniformState) {
+ return uniformState.orthographicIn3D ? 1 : 0;
+ }
+ }),
+
/**
* An automatic GLSL uniform representing a 3x3 normal transformation matrix that
* transforms normal vectors in model coordinates to eye coordinates.
diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js
index 27ced786160e..7c9194b3ce6d 100644
--- a/Source/Renderer/UniformState.js
+++ b/Source/Renderer/UniformState.js
@@ -873,6 +873,18 @@ define([
get : function() {
return this._invertClassificationColor;
}
+ },
+
+ /**
+ * Whether or not the current projection is orthographic in 3D.
+ *
+ * @memberOf UniformState.prototype
+ * @type {Boolean}
+ */
+ orthographicIn3D : {
+ get : function() {
+ return this._orthographicIn3D;
+ }
}
});
diff --git a/Source/Scene/BatchTable.js b/Source/Scene/BatchTable.js
index e32799823b04..bbe799c529c9 100644
--- a/Source/Scene/BatchTable.js
+++ b/Source/Scene/BatchTable.js
@@ -16,7 +16,8 @@ define([
'../Renderer/Sampler',
'../Renderer/Texture',
'../Renderer/TextureMagnificationFilter',
- '../Renderer/TextureMinificationFilter'
+ '../Renderer/TextureMinificationFilter',
+ './getUnpackFloatFunction'
], function(
Cartesian2,
Cartesian3,
@@ -35,7 +36,8 @@ define([
Sampler,
Texture,
TextureMagnificationFilter,
- TextureMinificationFilter) {
+ TextureMinificationFilter,
+ getUnpackFloatFunction) {
'use strict';
/**
@@ -226,48 +228,18 @@ define([
var scratchPackedFloatCartesian4 = new Cartesian4();
- var SHIFT_LEFT_8 = 256.0;
- var SHIFT_LEFT_16 = 65536.0;
- var SHIFT_LEFT_24 = 16777216.0;
-
- var SHIFT_RIGHT_8 = 1.0 / SHIFT_LEFT_8;
- var SHIFT_RIGHT_16 = 1.0 / SHIFT_LEFT_16;
- var SHIFT_RIGHT_24 = 1.0 / SHIFT_LEFT_24;
-
- var BIAS = 38.0;
-
- function unpackFloat(value) {
- var temp = value.w / 2.0;
- var exponent = Math.floor(temp);
- var sign = (temp - exponent) * 2.0;
- exponent = exponent - BIAS;
-
- sign = sign * 2.0 - 1.0;
- sign = -sign;
-
- if (exponent >= BIAS) {
- return sign < 0.0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
- }
-
- var unpacked = sign * value.x * SHIFT_RIGHT_8;
- unpacked += sign * value.y * SHIFT_RIGHT_16;
- unpacked += sign * value.z * SHIFT_RIGHT_24;
-
- return unpacked * Math.pow(10.0, exponent);
- }
-
function getPackedFloat(array, index, result) {
var packed = Cartesian4.unpack(array, index, scratchPackedFloatCartesian4);
- var x = unpackFloat(packed);
+ var x = Cartesian4.unpackFloat(packed);
packed = Cartesian4.unpack(array, index + 4, scratchPackedFloatCartesian4);
- var y = unpackFloat(packed);
+ var y = Cartesian4.unpackFloat(packed);
packed = Cartesian4.unpack(array, index + 8, scratchPackedFloatCartesian4);
- var z = unpackFloat(packed);
+ var z = Cartesian4.unpackFloat(packed);
packed = Cartesian4.unpack(array, index + 12, scratchPackedFloatCartesian4);
- var w = unpackFloat(packed);
+ var w = Cartesian4.unpackFloat(packed);
return Cartesian4.fromElements(x, y, z, w, result);
}
@@ -275,50 +247,18 @@ define([
if (!FeatureDetection.supportsTypedArrays()) {
return;
}
- var scratchFloatArray = new Float32Array(1);
-
- function packFloat(value, result) {
- scratchFloatArray[0] = value;
- value = scratchFloatArray[0];
-
- if (value === 0.0) {
- return Cartesian4.clone(Cartesian4.ZERO, result);
- }
-
- var sign = value < 0.0 ? 1.0 : 0.0;
- var exponent;
-
- if (!isFinite(value)) {
- value = 0.1;
- exponent = BIAS;
- } else {
- value = Math.abs(value);
- exponent = Math.floor(CesiumMath.logBase(value, 10)) + 1.0;
- value = value / Math.pow(10.0, exponent);
- }
-
- var temp = value * SHIFT_LEFT_8;
- result.x = Math.floor(temp);
- temp = (temp - result.x) * SHIFT_LEFT_8;
- result.y = Math.floor(temp);
- temp = (temp - result.y) * SHIFT_LEFT_8;
- result.z = Math.floor(temp);
- result.w = (exponent + BIAS) * 2.0 + sign;
-
- return result;
- }
function setPackedAttribute(value, array, index) {
- var packed = packFloat(value.x, scratchPackedFloatCartesian4);
+ var packed = Cartesian4.packFloat(value.x, scratchPackedFloatCartesian4);
Cartesian4.pack(packed, array, index);
- packed = packFloat(value.y, packed);
+ packed = Cartesian4.packFloat(value.y, packed);
Cartesian4.pack(packed, array, index + 4);
- packed = packFloat(value.z, packed);
+ packed = Cartesian4.packFloat(value.z, packed);
Cartesian4.pack(packed, array, index + 8);
- packed = packFloat(value.w, packed);
+ packed = Cartesian4.packFloat(value.w, packed);
Cartesian4.pack(packed, array, index + 12);
}
@@ -527,20 +467,7 @@ define([
return '';
}
- return 'float unpackFloat(vec4 value) \n' +
- '{ \n' +
- ' value *= 255.0; \n' +
- ' float temp = value.w / 2.0; \n' +
- ' float exponent = floor(temp); \n' +
- ' float sign = (temp - exponent) * 2.0; \n' +
- ' exponent = exponent - float(' + BIAS + '); \n' +
- ' sign = sign * 2.0 - 1.0; \n' +
- ' sign = -sign; \n' +
- ' float unpacked = sign * value.x * float(' + SHIFT_RIGHT_8 + '); \n' +
- ' unpacked += sign * value.y * float(' + SHIFT_RIGHT_16 + '); \n' +
- ' unpacked += sign * value.z * float(' + SHIFT_RIGHT_24 + '); \n' +
- ' return unpacked * pow(10.0, exponent); \n' +
- '} \n';
+ return getUnpackFloatFunction('unpackFloat');
}
function getComponentType(componentsPerAttribute) {
diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js
index 5ecb891e1a73..2f6f2a350dd0 100644
--- a/Source/Scene/Batched3DModel3DTileContent.js
+++ b/Source/Scene/Batched3DModel3DTileContent.js
@@ -1,5 +1,4 @@
define([
- '../Core/ClippingPlaneCollection',
'../Core/Color',
'../Core/defaultValue',
'../Core/defined',
@@ -20,7 +19,6 @@ define([
'./Model',
'./ModelUtility'
], function(
- ClippingPlaneCollection,
Color,
defaultValue,
defined,
@@ -69,6 +67,10 @@ define([
this._batchTable = undefined;
this._features = undefined;
+ // Populate from gltf when available
+ this._batchIdAttributeName = undefined;
+ this._diffuseAttributeOrUniformName = {};
+
/**
* @inheritdoc Cesium3DTileContent#featurePropertiesDirty
*/
@@ -206,11 +208,15 @@ define([
function getVertexShaderCallback(content) {
return function(vs, programId) {
var batchTable = content._batchTable;
- var gltf = content._model.gltf;
var handleTranslucent = !defined(content._tileset.classificationType);
- var batchIdAttributeName = getBatchIdAttributeName(gltf);
- var diffuseAttributeOrUniformName = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId);
- var callback = batchTable.getVertexShaderCallback(handleTranslucent, batchIdAttributeName, diffuseAttributeOrUniformName);
+
+ var gltf = content._model.gltf;
+ if (defined(gltf)) {
+ content._batchIdAttributeName = getBatchIdAttributeName(gltf);
+ content._diffuseAttributeOrUniformName[programId] = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId);
+ }
+
+ var callback = batchTable.getVertexShaderCallback(handleTranslucent, content._batchIdAttributeName, content._diffuseAttributeOrUniformName[programId]);
return defined(callback) ? callback(vs) : vs;
};
}
@@ -218,9 +224,13 @@ define([
function getPickVertexShaderCallback(content) {
return function(vs) {
var batchTable = content._batchTable;
+
var gltf = content._model.gltf;
- var batchIdAttributeName = getBatchIdAttributeName(gltf);
- var callback = batchTable.getPickVertexShaderCallback(batchIdAttributeName);
+ if (defined(gltf)) {
+ content._batchIdAttributeName = getBatchIdAttributeName(gltf);
+ }
+
+ var callback = batchTable.getPickVertexShaderCallback(content._batchIdAttributeName);
return defined(callback) ? callback(vs) : vs;
};
}
@@ -228,10 +238,13 @@ define([
function getFragmentShaderCallback(content) {
return function(fs, programId) {
var batchTable = content._batchTable;
- var gltf = content._model.gltf;
var handleTranslucent = !defined(content._tileset.classificationType);
- var diffuseAttributeOrUniformName = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId);
- var callback = batchTable.getFragmentShaderCallback(handleTranslucent, diffuseAttributeOrUniformName);
+
+ var gltf = content._model.gltf;
+ if (defined(gltf)) {
+ content._diffuseAttributeOrUniformName[programId] = ModelUtility.getDiffuseAttributeOrUniform(gltf, programId);
+ }
+ var callback = batchTable.getFragmentShaderCallback(handleTranslucent, content._diffuseAttributeOrUniformName[programId]);
return defined(callback) ? callback(fs) : fs;
};
}
@@ -379,15 +392,6 @@ define([
};
if (!defined(tileset.classificationType)) {
- var clippingPlanes;
- if (defined(tileset.clippingPlanes)) {
- clippingPlanes = tileset.clippingPlanes.clone();
- } else {
- clippingPlanes = new ClippingPlaneCollection({
- enabled : false
- });
- }
-
// PERFORMANCE_IDEA: patch the shader on demand, e.g., the first time show/color changes.
// The pick shader still needs to be patched.
content._model = new Model({
@@ -409,8 +413,7 @@ define([
pickFragmentShaderLoaded : batchTable.getPickFragmentShaderCallback(),
pickUniformMapLoaded : batchTable.getPickUniformMapCallback(),
addBatchIdToGeneratedShaders : (batchLength > 0), // If the batch table has values in it, generated shaders will need a batchId attribute
- pickObject : pickObject,
- clippingPlanes : clippingPlanes
+ pickObject : pickObject
});
} else {
// This transcodes glTF to an internal representation for geometry so we can take advantage of the re-batching of vector data.
@@ -503,12 +506,11 @@ define([
// Update clipping planes
var tilesetClippingPlanes = this._tileset.clippingPlanes;
- var modelClippingPlanes = this._model.clippingPlanes;
- if (defined(tilesetClippingPlanes)) {
- tilesetClippingPlanes.clone(modelClippingPlanes);
- modelClippingPlanes.enabled = tilesetClippingPlanes.enabled && this._tile._isClipped;
- } else if (defined(modelClippingPlanes) && modelClippingPlanes.enabled) {
- modelClippingPlanes.enabled = false;
+ if (this._tile.clippingPlanesDirty && defined(tilesetClippingPlanes)) {
+ // Dereference the clipping planes from the model if they are irrelevant.
+ // Link/Dereference directly to avoid ownership checks.
+ // This will also trigger synchronous shader regeneration to remove or add the clipping plane and color blending code.
+ this._model._clippingPlanes = (tilesetClippingPlanes.enabled && this._tile._isClipped) ? tilesetClippingPlanes : undefined;
}
this._model.update(frameState);
diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js
index 5ffb0114e887..e386a997586b 100644
--- a/Source/Scene/Cesium3DTile.js
+++ b/Source/Scene/Cesium3DTile.js
@@ -310,6 +310,16 @@ define([
*/
this._optimChildrenWithinParent = Cesium3DTileOptimizationHint.NOT_COMPUTED;
+ /**
+ * Tracks if the tile's relationship with a ClippingPlaneCollection has changed with regards
+ * to the ClippingPlaneCollection's state.
+ *
+ * @type {Boolean}
+ *
+ * @private
+ */
+ this.clippingPlanesDirty = false;
+
// Members that are updated every frame for tree traversal and rendering optimizations:
this._distanceToCamera = 0;
this._visibilityPlaneMask = 0;
@@ -329,6 +339,7 @@ define([
this._ancestorWithContent = undefined;
this._ancestorWithLoadedContent = undefined;
this._isClipped = true;
+ this._clippingPlanesState = 0; // encapsulates (_isClipped, clippingPlanes.enabled) and number/function
this._debugBoundingVolume = undefined;
this._debugContentBoundingVolume = undefined;
@@ -1048,6 +1059,23 @@ define([
content.update(tileset, frameState);
}
+ function updateClippingPlanes(tile, tileset) {
+ // Compute and compare ClippingPlanes state:
+ // - enabled-ness - are clipping planes enabled? is this tile clipped?
+ // - clipping plane count
+ // - clipping function (union v. intersection)
+ var clippingPlanes = tileset.clippingPlanes;
+ var currentClippingPlanesState = 0;
+ if (defined(clippingPlanes) && tile._isClipped && clippingPlanes.enabled) {
+ currentClippingPlanesState = clippingPlanes.clippingPlanesState();
+ }
+ // If clippingPlaneState for tile changed, mark clippingPlanesDirty so content can update
+ if (currentClippingPlanesState !== tile._clippingPlanesState) {
+ tile._clippingPlanesState = currentClippingPlanesState;
+ tile.clippingPlanesDirty = true;
+ }
+ }
+
/**
* Get the draw commands needed to render this tile.
*
@@ -1055,9 +1083,12 @@ define([
*/
Cesium3DTile.prototype.update = function(tileset, frameState) {
var initCommandLength = frameState.commandList.length;
+ updateClippingPlanes(this, tileset);
applyDebugSettings(this, tileset, frameState);
updateContent(this, tileset, frameState);
this._commandsLength = frameState.commandList.length - initCommandLength;
+
+ this.clippingPlanesDirty = false; // reset after content update
};
var scratchCommandList = [];
diff --git a/Source/Scene/Cesium3DTileBatchTable.js b/Source/Scene/Cesium3DTileBatchTable.js
index 528e2d7caaae..be54a96ac99c 100644
--- a/Source/Scene/Cesium3DTileBatchTable.js
+++ b/Source/Scene/Cesium3DTileBatchTable.js
@@ -1331,10 +1331,12 @@ define([
for (var i = commandStart; i < commandEnd; ++i) {
var command = commandList[i];
var derivedCommands = command.derivedCommands.tileset;
- if (!defined(derivedCommands)) {
+ // Command may be marked dirty from Model shader recompilation for clipping planes
+ if (!defined(derivedCommands) || command.dirty) {
derivedCommands = {};
command.derivedCommands.tileset = derivedCommands;
derivedCommands.originalCommand = deriveCommand(command);
+ command.dirty = false;
}
updateDerivedCommand(derivedCommands.originalCommand, command);
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index 699fc5d41595..ddfbdcab4d21 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -3,6 +3,7 @@ define([
'../Core/Cartesian3',
'../Core/Cartographic',
'../Core/Check',
+ '../Core/ClippingPlaneCollection',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
@@ -46,6 +47,7 @@ define([
Cartesian3,
Cartographic,
Check,
+ ClippingPlaneCollection,
defaultValue,
defined,
defineProperties,
@@ -111,7 +113,7 @@ define([
* @param {Number} [options.skipLevels=1] When skipLevelOfDetail
is true
, a constant defining the minimum number of levels to skip when loading tiles. When it is 0, no levels are skipped. Used in conjunction with skipScreenSpaceErrorFactor
to determine which tiles to load.
* @param {Boolean} [options.immediatelyLoadDesiredLevelOfDetail=false] When skipLevelOfDetail
is true
, only tiles that meet the maximum screen space error will ever be downloaded. Skipping factors are ignored and just the desired tiles are loaded.
* @param {Boolean} [options.loadSiblings=false] When skipLevelOfDetail
is true
, determines whether siblings of visible tiles are always downloaded during traversal.
- * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset. Clipping planes are not currently supported in Internet Explorer.
+ * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
* @param {ClassificationType} [options.classificationType] Determines whether terrain, 3D Tiles or both will be classified by this tileset. See {@link Cesium3DTileset#classificationType} for details about restrictions and limitations.
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid determining the size and shape of the globe.
* @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering.
@@ -547,11 +549,7 @@ define([
*/
this.loadSiblings = defaultValue(options.loadSiblings, false);
- /**
- * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset. Clipping planes are not currently supported in Internet Explorer.
- *
- * @type {ClippingPlaneCollection}
- */
+ this._clippingPlanes = undefined;
this.clippingPlanes = options.clippingPlanes;
/**
@@ -814,6 +812,19 @@ define([
return this._asset;
}
},
+ /**
+ * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
+ *
+ * @type {ClippingPlaneCollection}
+ */
+ clippingPlanes : {
+ get : function() {
+ return this._clippingPlanes;
+ },
+ set : function(value) {
+ ClippingPlaneCollection.setOwnership(value, this, '_clippingPlanes');
+ }
+ },
/**
* Gets the tileset's properties dictionary object, which contains metadata about per-feature properties.
@@ -1846,6 +1857,12 @@ define([
this._loadTimestamp = JulianDate.clone(frameState.time);
}
+ // Update clipping planes
+ var clippingPlanes = this._clippingPlanes;
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
+ clippingPlanes.update(frameState);
+ }
+
this._timeSinceLoad = Math.max(JulianDate.secondsDifference(frameState.time, this._loadTimestamp) * 1000, 0.0);
this._skipLevelOfDetail = this.skipLevelOfDetail && !defined(this._classificationType) && !this._disableSkipLevelOfDetail;
@@ -1930,6 +1947,9 @@ define([
// Destroy debug labels
this._tileDebugLabels = this._tileDebugLabels && this._tileDebugLabels.destroy();
+ // Destroy clipping plane collection
+ this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
+
// Traverse the tree and destroy all tiles
if (defined(this._root)) {
var stack = scratchStack;
diff --git a/Source/Scene/ClassificationType.js b/Source/Scene/ClassificationType.js
index 4d5f4f403965..2b92bb5f9d75 100644
--- a/Source/Scene/ClassificationType.js
+++ b/Source/Scene/ClassificationType.js
@@ -7,7 +7,7 @@ define([
/**
* Whether a classification affects terrain, 3D Tiles or both.
*
- * @exports ClassificationOption
+ * @exports ClassificationType
*/
var ClassificationType = {
/**
diff --git a/Source/Scene/DracoLoader.js b/Source/Scene/DracoLoader.js
new file mode 100644
index 000000000000..4821e4dc511c
--- /dev/null
+++ b/Source/Scene/DracoLoader.js
@@ -0,0 +1,197 @@
+define([
+ '../Core/arraySlice',
+ '../Core/ComponentDatatype',
+ '../Core/defined',
+ '../Core/FeatureDetection',
+ '../Core/TaskProcessor',
+ '../Renderer/Buffer',
+ '../Renderer/BufferUsage',
+ '../ThirdParty/GltfPipeline/ForEach',
+ '../ThirdParty/when'
+ ], function(
+ arraySlice,
+ ComponentDatatype,
+ defined,
+ FeatureDetection,
+ TaskProcessor,
+ Buffer,
+ BufferUsage,
+ ForEach,
+ when) {
+ 'use strict';
+
+ /**
+ * @private
+ */
+ function DracoLoader() {}
+
+ // Maximum concurrency to use when deocding draco models
+ DracoLoader._maxDecodingConcurrency = Math.max(FeatureDetection.hardwareConcurrency - 1, 1);
+
+ // Exposed for testing purposes
+ DracoLoader._decoderTaskProcessor = undefined;
+ DracoLoader._getDecoderTaskProcessor = function () {
+ if (!defined(DracoLoader._decoderTaskProcessor)) {
+ DracoLoader._decoderTaskProcessor = new TaskProcessor('decodeDraco', DracoLoader._maxDecodingConcurrency);
+ }
+
+ return DracoLoader._decoderTaskProcessor;
+ };
+
+ function hasExtension(model) {
+ return (defined(model.extensionsRequired.KHR_draco_mesh_compression)
+ || defined(model.extensionsUsed.KHR_draco_mesh_compression));
+ }
+
+ function addBufferToModelResources(model, buffer) {
+ var resourceBuffers = model._rendererResources.buffers;
+ var bufferViewId = Object.keys(resourceBuffers).length;
+ resourceBuffers[bufferViewId] = buffer;
+ model._geometryByteLength += buffer.sizeInBytes;
+
+ return bufferViewId;
+ }
+
+ function addNewVertexBuffer(typedArray, model, context) {
+ var vertexBuffer = Buffer.createVertexBuffer({
+ context : context,
+ typedArray : typedArray,
+ usage : BufferUsage.STATIC_DRAW
+ });
+ vertexBuffer.vertexArrayDestroyable = false;
+
+ return addBufferToModelResources(model, vertexBuffer);
+ }
+
+ function addNewIndexBuffer(typedArray, model, context) {
+ var indexBuffer = Buffer.createIndexBuffer({
+ context : context,
+ typedArray : typedArray,
+ usage : BufferUsage.STATIC_DRAW,
+ indexDatatype : ComponentDatatype.fromTypedArray(typedArray)
+ });
+ indexBuffer.vertexArrayDestroyable = false;
+
+ var bufferViewId = addBufferToModelResources(model, indexBuffer);
+ return {
+ bufferViewId: bufferViewId,
+ numberOfIndices : indexBuffer.numberOfIndices
+ };
+ }
+
+ function addDecodededBuffers(primitive, model, context) {
+ return function (result) {
+ var decodedIndexBuffer = addNewIndexBuffer(result.indexArray, model, context);
+
+ var attributes = {};
+ var decodedAttributeData = result.attributeData;
+ for (var attributeName in decodedAttributeData) {
+ if (decodedAttributeData.hasOwnProperty(attributeName)) {
+ var attribute = decodedAttributeData[attributeName];
+ var vertexArray = attribute.array;
+ var vertexBufferView = addNewVertexBuffer(vertexArray, model, context);
+
+ var data = attribute.data;
+ data.bufferView = vertexBufferView;
+
+ attributes[attributeName] = data;
+ }
+ }
+
+ model._decodedData[primitive.mesh + '.primitive.' + primitive.primitive] = {
+ bufferView : decodedIndexBuffer.bufferViewId,
+ numberOfIndices : decodedIndexBuffer.numberOfIndices,
+ attributes : attributes
+ };
+ };
+ }
+
+ function scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context) {
+ var taskData = loadResources.primitivesToDecode.peek();
+ if (!defined(taskData)) {
+ // All primitives are processing
+ return;
+ }
+
+ var promise = decoderTaskProcessor.scheduleTask(taskData, [taskData.array.buffer]);
+ if (!defined(promise)) {
+ // Cannot schedule another task this frame
+ return;
+ }
+
+ loadResources.primitivesToDecode.dequeue();
+ return promise.then(addDecodededBuffers(taskData, model, context));
+ }
+
+ /**
+ * Parses draco extension on model primitives and
+ * adds the decoding data to the model's load resources.
+ *
+ * @private
+ */
+ DracoLoader.parse = function(model) {
+ if (!hasExtension(model)) {
+ return;
+ }
+
+ var loadResources = model._loadResources;
+ loadResources.decoding = true;
+
+ var gltf = model.gltf;
+ ForEach.mesh(gltf, function(mesh, meshId) {
+ ForEach.meshPrimitive(mesh, function(primitive, primitiveId) {
+ if (!defined(primitive.extensions)) {
+ return;
+ }
+
+ var compressionData = primitive.extensions.KHR_draco_mesh_compression;
+ if (!defined(compressionData)) {
+ return;
+ }
+
+ var bufferView = gltf.bufferViews[compressionData.bufferView];
+ var typedArray = arraySlice(gltf.buffers[bufferView.buffer].extras._pipeline.source, bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength);
+
+ loadResources.primitivesToDecode.enqueue({
+ mesh : meshId,
+ primitive : primitiveId,
+ array : typedArray,
+ bufferView : bufferView,
+ compressedAttributes : compressionData.attributes
+ });
+ });
+ });
+ };
+
+ /**
+ * Schedules decoding tasks available this frame.
+ * @private
+ */
+ DracoLoader.decode = function(model, context) {
+ if (!hasExtension(model)) {
+ return when.resolve();
+ }
+
+ var loadResources = model._loadResources;
+ if (loadResources.primitivesToDecode.length === 0) {
+ // No more tasks to schedule
+ return when.resolve();
+ }
+
+ var decoderTaskProcessor = DracoLoader._getDecoderTaskProcessor();
+ var decodingPromises = [];
+
+ var promise = scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context);
+ while (defined(promise)) {
+ decodingPromises.push(promise);
+ promise = scheduleDecodingTask(decoderTaskProcessor, model, loadResources, context);
+ }
+
+ return when.all(decodingPromises).then(function () {
+ // Done decoding when there are no more active tasks
+ loadResources.decoding = (decoderTaskProcessor._activeTasks !== 0);
+ });
+ };
+
+ return DracoLoader;
+});
diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js
index 343295c50c1d..5d391dbebf31 100644
--- a/Source/Scene/Globe.js
+++ b/Source/Scene/Globe.js
@@ -266,7 +266,7 @@ define([
}
},
/**
- * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane. Clipping planes are not currently supported in Internet Explorer.
+ * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane.
*
* @memberof Globe.prototype
* @type {ClippingPlaneCollection}
diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js
index c46fe650b6bf..85c775b1c00c 100644
--- a/Source/Scene/GlobeSurfaceShaderSet.js
+++ b/Source/Scene/GlobeSurfaceShaderSet.js
@@ -1,22 +1,27 @@
define([
+ '../Core/ClippingPlaneCollection',
'../Core/defined',
'../Core/destroyObject',
'../Core/TerrainQuantization',
'../Renderer/ShaderProgram',
- '../Scene/SceneMode'
+ '../Scene/SceneMode',
+ './getClippingFunction'
], function(
+ ClippingPlaneCollection,
defined,
destroyObject,
TerrainQuantization,
ShaderProgram,
- SceneMode) {
+ SceneMode,
+ getClippingFunction) {
'use strict';
- function GlobeSurfaceShader(numberOfDayTextures, flags, material, shaderProgram) {
+ function GlobeSurfaceShader(numberOfDayTextures, flags, material, shaderProgram, clippingShaderState) {
this.numberOfDayTextures = numberOfDayTextures;
this.flags = flags;
this.material = material;
this.shaderProgram = shaderProgram;
+ this.clippingShaderState = clippingShaderState;
}
/**
@@ -64,7 +69,7 @@ define([
return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection;
}
- GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog, enableClippingPlanes, unionClippingRegions) {
+ GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog, enableClippingPlanes, clippingPlanes) {
var quantization = 0;
var quantizationDefine = '';
@@ -93,27 +98,36 @@ define([
(applySplit << 15) |
(enableClippingPlanes << 16);
+ var currentClippingShaderState = 0;
+ if (defined(clippingPlanes)) {
+ currentClippingShaderState = enableClippingPlanes ? clippingPlanes.clippingPlanesState() : 0;
+ }
var surfaceShader = surfaceTile.surfaceShader;
if (defined(surfaceShader) &&
surfaceShader.numberOfDayTextures === numberOfDayTextures &&
surfaceShader.flags === flags &&
- surfaceShader.material === this.material) {
+ surfaceShader.material === this.material &&
+ surfaceShader.clippingShaderState === currentClippingShaderState) {
return surfaceShader.shaderProgram;
}
- // New tile, or tile changed number of textures or flags.
+ // New tile, or tile changed number of textures, flags, or clipping planes
var shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures];
if (!defined(shadersByFlags)) {
shadersByFlags = this._shadersByTexturesFlags[numberOfDayTextures] = [];
}
surfaceShader = shadersByFlags[flags];
- if (!defined(surfaceShader) || surfaceShader.material !== this.material) {
+ if (!defined(surfaceShader) || surfaceShader.material !== this.material || surfaceShader.clippingShaderState !== currentClippingShaderState) {
// Cache miss - we've never seen this combination of numberOfDayTextures and flags before.
var vs = this.baseVertexShaderSource.clone();
var fs = this.baseFragmentShaderSource.clone();
+ if (currentClippingShaderState !== 0) {
+ fs.sources.unshift(getClippingFunction(clippingPlanes)); // Need to go before GlobeFS
+ }
+
vs.defines.push(quantizationDefine);
fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures);
@@ -167,10 +181,6 @@ define([
if (enableClippingPlanes) {
fs.defines.push('ENABLE_CLIPPING_PLANES');
-
- if (unionClippingRegions) {
- fs.defines.push('UNION_CLIPPING_REGIONS');
- }
}
var computeDayColor = '\
@@ -212,7 +222,7 @@ define([
attributeLocations : terrainEncoding.getAttributeLocations()
});
- surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(numberOfDayTextures, flags, this.material, shader);
+ surfaceShader = shadersByFlags[flags] = new GlobeSurfaceShader(numberOfDayTextures, flags, this.material, shader, currentClippingShaderState);
}
surfaceTile.surfaceShader = surfaceShader;
diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js
index ddf1fc10d641..9d9ea96e7e7b 100644
--- a/Source/Scene/GlobeSurfaceTileProvider.js
+++ b/Source/Scene/GlobeSurfaceTileProvider.js
@@ -172,7 +172,7 @@ define([
* @type {ClippingPlaneCollection}
* @private
*/
- this.clippingPlanes = undefined;
+ this._clippingPlanes = undefined;
}
defineProperties(GlobeSurfaceTileProvider.prototype, {
@@ -302,6 +302,21 @@ define([
this._quadtree.invalidateAllTiles();
}
}
+ },
+ /**
+ * The {@link ClippingPlaneCollection} used to selectively disable rendering the tileset.
+ *
+ * @type {ClippingPlaneCollection}
+ *
+ * @private
+ */
+ clippingPlanes : {
+ get : function() {
+ return this._clippingPlanes;
+ },
+ set : function(value) {
+ ClippingPlaneCollection.setOwnership(value, this, '_clippingPlanes');
+ }
}
});
@@ -396,7 +411,11 @@ define([
tiles.length = 0;
}
}
-
+ // update clipping planes
+ var clippingPlanes = this._clippingPlanes;
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
+ clippingPlanes.update(frameState);
+ }
this._usedDrawCommands = 0;
};
@@ -548,7 +567,7 @@ define([
}
}
- var clippingPlanes = this.clippingPlanes;
+ var clippingPlanes = this._clippingPlanes;
if (defined(clippingPlanes) && clippingPlanes.enabled) {
var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume);
tile.isClipped = (planeIntersection !== Intersect.INSIDE);
@@ -666,6 +685,8 @@ define([
*/
GlobeSurfaceTileProvider.prototype.destroy = function() {
this._tileProvider = this._tileProvider && this._tileProvider.destroy();
+ this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
+
return destroyObject(this);
};
@@ -826,7 +847,8 @@ define([
}
};
- function createTileUniformMap(frameState) {
+ var scratchClippingPlaneMatrix = new Matrix4();
+ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
var uniformMap = {
u_initialColor : function() {
return this.properties.initialColor;
@@ -914,11 +936,17 @@ define([
u_dayTextureSplit : function() {
return this.properties.dayTextureSplit;
},
- u_clippingPlanesLength : function() {
- return this.properties.clippingPlanes.length;
- },
u_clippingPlanes : function() {
- return this.properties.clippingPlanes;
+ var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
+ if (defined(clippingPlanes) && defined(clippingPlanes.texture)) {
+ // Check in case clippingPlanes hasn't been updated yet.
+ return clippingPlanes.texture;
+ }
+ return frameState.context.defaultTexture;
+ },
+ u_clippingPlanesMatrix : function() {
+ var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
+ return defined(clippingPlanes) ? Matrix4.multiply(frameState.context.uniformState.view, clippingPlanes.modelMatrix, scratchClippingPlaneMatrix) : Matrix4.IDENTITY;
},
u_clippingPlanesEdgeStyle : function() {
var style = this.properties.clippingPlanesEdgeColor;
@@ -963,7 +991,6 @@ define([
minMaxHeight : new Cartesian2(),
scaleAndBias : new Matrix4(),
- clippingPlanes : [],
clippingPlanesEdgeColor : Color.clone(Color.WHITE),
clippingPlanesEdgeWidth : 0.0
}
@@ -1211,7 +1238,7 @@ define([
command.boundingVolume = new BoundingSphere();
command.orientedBoundingBox = undefined;
- uniformMap = createTileUniformMap(frameState);
+ uniformMap = createTileUniformMap(frameState, tileProvider);
tileProvider._drawCommands.push(command);
tileProvider._uniformMaps.push(uniformMap);
@@ -1342,37 +1369,18 @@ define([
Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias);
// update clipping planes
- var clippingPlanes = tileProvider.clippingPlanes;
- var length = 0;
-
- if (defined(clippingPlanes) && tile.isClipped) {
- length = clippingPlanes.length;
- }
-
- var packedPlanes = uniformMapProperties.clippingPlanes;
- var packedLength = packedPlanes.length;
- if (packedLength !== length) {
- packedPlanes.length = length;
-
- for (var i = packedLength; i < length; ++i) {
- packedPlanes[i] = new Cartesian4();
- }
- }
-
- if (defined(clippingPlanes) && clippingPlanes.enabled && tile.isClipped) {
- clippingPlanes.transformAndPackPlanes(context.uniformState.view, packedPlanes);
+ var clippingPlanes = tileProvider._clippingPlanes;
+ var clippingPlanesEnabled = defined(clippingPlanes) && clippingPlanes.enabled && tile.isClipped;
+ if (clippingPlanesEnabled) {
uniformMapProperties.clippingPlanesEdgeColor = Color.clone(clippingPlanes.edgeColor, uniformMapProperties.clippingPlanesEdgeColor);
uniformMapProperties.clippingPlanesEdgeWidth = clippingPlanes.edgeWidth;
}
- var clippingPlanesEnabled = defined(clippingPlanes) && clippingPlanes.enabled && (uniformMapProperties.clippingPlanes.length > 0) && ClippingPlaneCollection.isSupported();
- var unionClippingRegions = clippingPlanesEnabled ? clippingPlanes.unionClippingRegions : false;
-
if (defined(tileProvider.uniformMap)) {
uniformMap = combine(uniformMap, tileProvider.uniformMap);
}
- command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog, clippingPlanesEnabled, unionClippingRegions);
+ command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog, clippingPlanesEnabled, clippingPlanes);
command.castShadows = castShadows;
command.receiveShadows = receiveShadows;
command.renderState = renderState;
diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js
index 1373144e21bb..01f65513809f 100644
--- a/Source/Scene/Instanced3DModel3DTileContent.js
+++ b/Source/Scene/Instanced3DModel3DTileContent.js
@@ -1,7 +1,6 @@
define([
'../Core/AttributeCompression',
'../Core/Cartesian3',
- '../Core/ClippingPlaneCollection',
'../Core/Color',
'../Core/ComponentDatatype',
'../Core/defaultValue',
@@ -29,7 +28,6 @@ define([
], function(
AttributeCompression,
Cartesian3,
- ClippingPlaneCollection,
Color,
ComponentDatatype,
defaultValue,
@@ -511,24 +509,21 @@ define([
this._modelInstanceCollection.modelMatrix = this._tile.computedTransform;
this._modelInstanceCollection.shadows = this._tileset.shadows;
this._modelInstanceCollection.debugWireframe = this._tileset.debugWireframe;
- this._modelInstanceCollection.update(frameState);
- // Update clipping planes
- var tilesetClippingPlanes = this._tileset.clippingPlanes;
var model = this._modelInstanceCollection._model;
- var modelClippingPlanes = model.clippingPlanes;
- if (defined(tilesetClippingPlanes)) {
- if (!defined(modelClippingPlanes)) {
- model.clippingPlanes = new ClippingPlaneCollection();
- modelClippingPlanes = model.clippingPlanes;
- }
- tilesetClippingPlanes.clone(modelClippingPlanes);
- modelClippingPlanes.enabled = tilesetClippingPlanes.enabled && this._tile._isClipped;
- } else if (defined(modelClippingPlanes) && modelClippingPlanes.enabled) {
- modelClippingPlanes.enabled = false;
+ if (defined(model)) {
+ // Update for clipping planes
+ var tilesetClippingPlanes = this._tileset.clippingPlanes;
+ if (this._tile.clippingPlanesDirty && defined(tilesetClippingPlanes)) {
+ // Dereference the clipping planes from the model if they are irrelevant - saves on shading
+ // Link/Dereference directly to avoid ownership checks.
+ model._clippingPlanes = (tilesetClippingPlanes.enabled && this._tile._isClipped) ? tilesetClippingPlanes : undefined;
+ }
}
+ this._modelInstanceCollection.update(frameState);
+
// If any commands were pushed, add derived commands
var commandEnd = frameState.commandList.length;
if ((commandStart < commandEnd) && frameState.passes.render) {
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 5a117e19c976..85990ae8a704 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -63,6 +63,8 @@ define([
'./Axis',
'./BlendingState',
'./ColorBlendMode',
+ './DracoLoader',
+ './getClippingFunction',
'./HeightReference',
'./JobType',
'./ModelAnimationCache',
@@ -139,6 +141,8 @@ define([
Axis,
BlendingState,
ColorBlendMode,
+ DracoLoader,
+ getClippingFunction,
HeightReference,
JobType,
ModelAnimationCache,
@@ -267,7 +271,7 @@ define([
* @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the colorBlendMode
is MIX
. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
* @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts.
* @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels.
- * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model. Clipping planes are not currently supported in Internet Explorer.
+ * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
*
* @exception {DeveloperError} bgltf is not a valid Binary glTF file.
* @exception {DeveloperError} Only glTF Binary version 1 is supported.
@@ -490,6 +494,7 @@ define([
this.color = defaultValue(options.color, Color.WHITE);
this._color = new Color();
this._colorPreviousAlpha = 1.0;
+ this._hasPremultipliedAlpha = false;
/**
* Defines how the color blends with the model.
@@ -511,12 +516,12 @@ define([
*/
this.colorBlendAmount = defaultValue(options.colorBlendAmount, 0.5);
- /**
- * The {@link ClippingPlaneCollection} used to selectively disable rendering the model. Clipping planes are not currently supported in Internet Explorer.
- *
- * @type {ClippingPlaneCollection}
- */
+ this._colorShadingEnabled = isColorShadingEnabled(this);
+
+ this._clippingPlanes = undefined;
this.clippingPlanes = options.clippingPlanes;
+ // Used for checking if shaders need to be regenerated due to clipping plane changes.
+ this._clippingPlanesState = 0;
/**
* This property is for debugging only; it is not for production use nor is it optimized.
@@ -616,6 +621,7 @@ define([
this._cachedRendererResources = undefined;
this._loadRendererResourcesFromCache = false;
this._updatedGltfVersion = false;
+ this._decodedData = {};
this._cachedGeometryByteLength = 0;
this._cachedTexturesByteLength = 0;
@@ -623,6 +629,12 @@ define([
this._texturesByteLength = 0;
this._trianglesLength = 0;
+ // Hold references to programs and shaders for shader reconstruction.
+ // Hold these separately because _cachedGltf may get released (this.releaseGltfJson)
+ this._sourcePrograms = undefined;
+ this._sourceShaders = undefined;
+ this._quantizedVertexShaders = {};
+
this._nodeCommands = [];
this._pickIds = [];
@@ -631,8 +643,6 @@ define([
this._rtcCenterEye = undefined; // in eye coordinates
this._rtcCenter3D = undefined; // in world coordinates
this._rtcCenter2D = undefined; // in projected world coordinates
-
- this._packedClippingPlanes = [];
}
defineProperties(Model.prototype, {
@@ -999,6 +1009,26 @@ define([
get : function() {
return this._cachedTexturesByteLength;
}
+ },
+
+ /**
+ * The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
+ *
+ * @memberof Model.prototype
+ *
+ * @type {ClippingPlaneCollection}
+ */
+ clippingPlanes : {
+ get : function() {
+ return this._clippingPlanes;
+ },
+ set : function(value) {
+ if (value === this._clippingPlanes) {
+ return;
+ }
+ // Handle destroying, checking of unknown, checking for existing ownership
+ ClippingPlaneCollection.setOwnership(value, this, '_clippingPlanes');
+ }
}
});
@@ -1006,6 +1036,15 @@ define([
return context.stencilBuffer;
}
+ function isColorShadingEnabled(model) {
+ return !Color.equals(model.color, Color.WHITE) || (model.colorBlendMode !== ColorBlendMode.HIGHLIGHT);
+ }
+
+ function isClippingEnabled(model) {
+ var clippingPlanes = model._clippingPlanes;
+ return defined(clippingPlanes) && clippingPlanes.enabled;
+ }
+
/**
* Determines if silhouettes are supported.
*
@@ -1060,7 +1099,7 @@ define([
* @param {Number} [options.colorBlendAmount=0.5] Value used to determine the color strength when the colorBlendMode
is MIX
. A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with any value in-between resulting in a mix of the two.
* @param {Color} [options.silhouetteColor=Color.RED] The silhouette color. If more than 256 models have silhouettes enabled, there is a small chance that overlapping models will have minor artifacts.
* @param {Number} [options.silhouetteSize=0.0] The size of the silhouette in pixels.
- * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model. Clipping planes are not currently supported in Internet Explorer.
+ * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
*
* @returns {Model} The newly created model.
*
@@ -1304,9 +1343,13 @@ define([
///////////////////////////////////////////////////////////////////////////
function getFailedLoadFunction(model, type, path) {
- return function() {
+ return function(error) {
model._state = ModelState.FAILED;
- model._readyPromise.reject(new RuntimeError('Failed to load ' + type + ': ' + path));
+ var message = 'Failed to load ' + type + ': ' + path;
+ if (defined(error)) {
+ message += '\n' + error.message;
+ }
+ model._readyPromise.reject(new RuntimeError(message));
};
}
@@ -1369,8 +1412,11 @@ define([
// through glTF accessors to create the bufferview's index buffer.
ForEach.accessor(model.gltf, function(accessor) {
var bufferViewId = accessor.bufferView;
- var bufferView = bufferViews[bufferViewId];
+ if (!defined(bufferViewId)) {
+ return;
+ }
+ var bufferView = bufferViews[bufferViewId];
if ((bufferView.target === WebGLConstants.ELEMENT_ARRAY_BUFFER) && !defined(indexBufferIds[bufferViewId])) {
indexBufferIds[bufferViewId] = true;
indexBuffersToCreate.enqueue({
@@ -1875,39 +1921,99 @@ define([
///////////////////////////////////////////////////////////////////////////
+ // When building programs for the first time, do not include modifiers for clipping planes and color
+ // since this is the version of the program that will be cached.
function createProgram(id, model, context) {
- var programs = model.gltf.programs;
- var shaders = model.gltf.shaders;
- var program = programs[id];
+ var program = model._sourcePrograms[id];
+ var shaders = model._sourceShaders;
+ var quantizedVertexShaders = model._quantizedVertexShaders;
- var attributeLocations = createAttributeLocations(model, program.attributes);
var vs = shaders[program.vertexShader].extras._pipeline.source;
var fs = shaders[program.fragmentShader].extras._pipeline.source;
- // Add pre-created attributes to attributeLocations
- var attributesLength = program.attributes.length;
- var precreatedAttributes = model._precreatedAttributes;
- if (defined(precreatedAttributes)) {
- for (var attrName in precreatedAttributes) {
- if (precreatedAttributes.hasOwnProperty(attrName)) {
- attributeLocations[attrName] = attributesLength++;
- }
+ if (model.extensionsUsed.WEB3D_quantized_attributes) {
+ var quantizedVS = quantizedVertexShaders[id];
+ if (!defined(quantizedVS)) {
+ quantizedVS = modifyShaderForQuantizedAttributes(vs, id, model);
+ quantizedVertexShaders[id] = quantizedVS;
+ }
+ vs = quantizedVS;
+ }
+
+ var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
+ var drawFS = modifyShader(fs, id, model._fragmentShaderLoaded);
+
+ var pickFS, pickVS;
+ if (model.allowPicking) {
+ // PERFORMANCE_IDEA: Can optimize this shader with a glTF hint. https://github.com/KhronosGroup/glTF/issues/181
+ pickVS = modifyShader(vs, id, model._pickVertexShaderLoaded);
+ pickFS = modifyShader(fs, id, model._pickFragmentShaderLoaded);
+
+ if (!model._pickFragmentShaderLoaded) {
+ pickFS = ShaderSource.createPickFragmentShaderSource(fs, 'uniform');
}
}
+ createAttributesAndProgram(id, drawFS, drawVS, pickFS, pickVS, model, context);
+ }
+
+ function recreateProgram(id, model, context) {
+ var program = model._sourcePrograms[id];
+ var shaders = model._sourceShaders;
+ var quantizedVertexShaders = model._quantizedVertexShaders;
+
+ var clippingPlaneCollection = model.clippingPlanes;
+ var addClippingPlaneCode = isClippingEnabled(model);
+
+ var vs = shaders[program.vertexShader].extras._pipeline.source;
+ var fs = shaders[program.fragmentShader].extras._pipeline.source;
if (model.extensionsUsed.WEB3D_quantized_attributes) {
- vs = modifyShaderForQuantizedAttributes(vs, id, model);
+ vs = quantizedVertexShaders[id];
}
- var premultipliedAlpha = hasPremultipliedAlpha(model);
- var finalFS = modifyShaderForColor(fs, premultipliedAlpha);
- if (ClippingPlaneCollection.isSupported()) {
- finalFS = modifyShaderForClippingPlanes(finalFS);
+ var finalFS = fs;
+ if (isColorShadingEnabled(model)) {
+ finalFS = Model._modifyShaderForColor(finalFS, model._hasPremultipliedAlpha);
+ }
+ if (addClippingPlaneCode) {
+ finalFS = modifyShaderForClippingPlanes(finalFS, clippingPlaneCollection);
}
var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
var drawFS = modifyShader(finalFS, id, model._fragmentShaderLoaded);
+ var pickFS, pickVS;
+ if (model.allowPicking) {
+ // PERFORMANCE_IDEA: Can optimize this shader with a glTF hint. https://github.com/KhronosGroup/glTF/issues/181
+ pickVS = modifyShader(vs, id, model._pickVertexShaderLoaded);
+ pickFS = modifyShader(fs, id, model._pickFragmentShaderLoaded);
+
+ if (!model._pickFragmentShaderLoaded) {
+ pickFS = ShaderSource.createPickFragmentShaderSource(fs, 'uniform');
+ }
+
+ if (addClippingPlaneCode) {
+ pickFS = modifyShaderForClippingPlanes(pickFS, clippingPlaneCollection);
+ }
+ }
+ createAttributesAndProgram(id, drawFS, drawVS, pickFS, pickVS, model, context);
+ }
+
+ function createAttributesAndProgram(id, drawFS, drawVS, pickFS, pickVS, model, context) {
+ var program = model._sourcePrograms[id];
+ var attributeLocations = createAttributeLocations(model, program.attributes);
+
+ // Add pre-created attributes to attributeLocations
+ var attributesLength = program.attributes.length;
+ var precreatedAttributes = model._precreatedAttributes;
+ if (defined(precreatedAttributes)) {
+ for (var attrName in precreatedAttributes) {
+ if (precreatedAttributes.hasOwnProperty(attrName)) {
+ attributeLocations[attrName] = attributesLength++;
+ }
+ }
+ }
+
drawVS = ModelUtility.modifyVertexShaderForLogDepth(model.gltf, drawVS);
drawFS = ModelUtility.modifyFragmentShaderForLogDepth(drawFS);
@@ -1919,14 +2025,6 @@ define([
});
if (model.allowPicking) {
- // PERFORMANCE_IDEA: Can optimize this shader with a glTF hint. https://github.com/KhronosGroup/glTF/issues/181
- var pickVS = modifyShader(vs, id, model._pickVertexShaderLoaded);
- var pickFS = modifyShader(fs, id, model._pickFragmentShaderLoaded);
-
- if (!model._pickFragmentShaderLoaded) {
- pickFS = ShaderSource.createPickFragmentShaderSource(fs, 'uniform');
- }
-
pickVS = ModelUtility.modifyVertexShaderForLogDepth(model.gltf, pickVS);
pickFS = ModelUtility.modifyFragmentShaderForLogDepth(pickFS);
@@ -2393,6 +2491,7 @@ define([
for (var i = 0; i < primitivesLength; ++i) {
var primitive = primitives[i];
+ var decodedData = model._decodedData[meshId + '.primitive.' + i];
// GLTF_SPEC: This does not take into account attribute arrays,
// indicated by when an attribute points to a parameter with a
@@ -2412,7 +2511,27 @@ define([
// Skip if the attribute is not used by the material, e.g., because the asset was exported
// with an attribute that wasn't used and the asset wasn't optimized.
if (defined(attributeLocation)) {
+ // Use attributes of previously decoded draco geometry
+ if (defined(decodedData)) {
+ var decodedAttributes = decodedData.attributes;
+ if (decodedAttributes.hasOwnProperty(attributeName)) {
+ var decodedAttribute = decodedAttributes[attributeName];
+ attributes.push({
+ index : attributeLocation,
+ vertexBuffer : rendererBuffers[decodedAttribute.bufferView],
+ componentsPerAttribute : decodedAttribute.componentsPerAttribute,
+ componentDatatype : decodedAttribute.componentDatatype,
+ normalize: decodedAttribute.normalized,
+ offsetInBytes : decodedAttribute.byteOffset,
+ strideInBytes : decodedAttribute.byteStride
+ });
+
+ continue;
+ }
+ }
+
var a = accessors[primitiveAttributes[attributeName]];
+
var normalize = false;
if (defined(a.normalized) && a.normalized) {
normalize = true;
@@ -2449,7 +2568,14 @@ define([
var indexBuffer;
if (defined(primitive.indices)) {
var accessor = accessors[primitive.indices];
- indexBuffer = rendererBuffers[accessor.bufferView];
+ var bufferView = accessor.bufferView;
+
+ // Used decoded draco buffer if available
+ if (defined(decodedData)) {
+ bufferView = decodedData.bufferView;
+ }
+
+ indexBuffer = rendererBuffers[bufferView];
}
rendererVertexArrays[meshId + '.primitive.' + i] = new VertexArray({
context : context,
@@ -2515,7 +2641,7 @@ define([
var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]);
// Change the render state to use traditional alpha blending instead of premultiplied alpha blending
- if (booleanStates[WebGLConstants.BLEND] && hasPremultipliedAlpha(model)) {
+ if (booleanStates[WebGLConstants.BLEND] && model._hasPremultipliedAlpha) {
if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) {
blendFuncSeparate[0] = WebGLConstants.SRC_ALPHA;
blendFuncSeparate[1] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
@@ -2800,33 +2926,21 @@ define([
};
}
- function createClippingPlanesLengthFunction(model) {
- return function() {
- return model._packedClippingPlanes.length;
- };
- }
-
- function createClippingPlanesUnionRegionsFunction(model) {
+ var scratchClippingPlaneMatrix = new Matrix4();
+ function createClippingPlanesMatrixFunction(model) {
return function() {
var clippingPlanes = model.clippingPlanes;
if (!defined(clippingPlanes)) {
- return false;
+ return Matrix4.IDENTITY;
}
-
- return clippingPlanes.unionClippingRegions;
+ return Matrix4.multiply(model._modelViewMatrix, clippingPlanes.modelMatrix, scratchClippingPlaneMatrix);
};
}
function createClippingPlanesFunction(model) {
return function() {
var clippingPlanes = model.clippingPlanes;
- var packedPlanes = model._packedClippingPlanes;
-
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
- clippingPlanes.transformAndPackPlanes(model._modelViewMatrix, packedPlanes);
- }
-
- return packedPlanes;
+ return (!defined(clippingPlanes) || !clippingPlanes.enabled) ? model._defaultTexture : clippingPlanes.texture;
};
}
@@ -2896,6 +3010,7 @@ define([
var material = materials[primitive.material];
var technique = techniques[material.technique];
var programId = technique.program;
+ var decodedData = model._decodedData[id + '.primitive.' + i];
var boundingSphere;
var positionAccessor = primitive.attributes.POSITION;
@@ -2909,6 +3024,12 @@ define([
var count;
if (defined(ix)) {
count = ix.count;
+
+ // Use indices of the previously decoded Draco geometry.
+ if (defined(decodedData)) {
+ count = decodedData.numberOfIndices;
+ }
+
offset = (ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType)); // glTF has offset in bytes. Cesium has offsets in indices
}
else {
@@ -2938,10 +3059,9 @@ define([
uniformMap = combine(uniformMap, {
gltf_color : createColorFunction(model),
gltf_colorBlend : createColorBlendFunction(model),
- gltf_clippingPlanesLength: createClippingPlanesLengthFunction(model),
- gltf_clippingPlanesUnionRegions: createClippingPlanesUnionRegionsFunction(model),
- gltf_clippingPlanes: createClippingPlanesFunction(model, context),
- gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(model)
+ gltf_clippingPlanes: createClippingPlanesFunction(model),
+ gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(model),
+ gltf_clippingPlanesMatrix: createClippingPlanesMatrixFunction(model)
});
// Allow callback to modify the uniformMap
@@ -2981,7 +3101,7 @@ define([
vertexArray : vertexArray,
count : count,
offset : offset,
- shaderProgram : rendererPrograms[technique.program],
+ shaderProgram : rendererPrograms[programId],
castShadows : castShadows,
receiveShadows : receiveShadows,
uniformMap : uniformMap,
@@ -3022,7 +3142,7 @@ define([
vertexArray : vertexArray,
count : count,
offset : offset,
- shaderProgram : rendererPickPrograms[technique.program],
+ shaderProgram : rendererPickPrograms[programId],
uniformMap : pickUniformMap,
renderState : rs,
owner : owner,
@@ -3058,12 +3178,13 @@ define([
silhouetteColorCommand2D : undefined,
// Generated on demand when color alpha is less than 1.0
translucentCommand : undefined,
- translucentCommand2D : undefined
+ translucentCommand2D : undefined,
+ // For updating node commands on shader reconstruction
+ programId : programId
};
runtimeNode.commands.push(nodeCommand);
nodeCommands.push(nodeCommand);
}
-
}
function createRuntimeNodes(model, context, scene3DOnly) {
@@ -3192,6 +3313,11 @@ define([
var context = frameState.context;
var scene3DOnly = frameState.scene3DOnly;
+ // Retain references to updated source shaders and programs for rebuilding as needed
+ model._sourcePrograms = model.gltf.programs;
+ model._sourceShaders = model.gltf.shaders;
+ model._hasPremultipliedAlpha = hasPremultipliedAlpha(model);
+
ModelUtility.checkSupportedGlExtensions(model.gltf.glExtensionsUsed, context);
if (model._loadRendererResourcesFromCache) {
var resources = model._rendererResources;
@@ -3515,14 +3641,14 @@ define([
return translucentCommand;
}
- function updateColor(model, frameState) {
+ function updateColor(model, frameState, forceDerive) {
// Generate translucent commands when the blend color has an alpha in the range (0.0, 1.0) exclusive
var scene3DOnly = frameState.scene3DOnly;
var alpha = model.color.alpha;
if ((alpha > 0.0) && (alpha < 1.0)) {
var nodeCommands = model._nodeCommands;
var length = nodeCommands.length;
- if (!defined(nodeCommands[0].translucentCommand)) {
+ if (!defined(nodeCommands[0].translucentCommand) || forceDerive) {
for (var i = 0; i < length; ++i) {
var nodeCommand = nodeCommands[i];
var command = nodeCommand.command;
@@ -3735,42 +3861,29 @@ define([
}
}
- function modifyShaderForClippingPlanes(shader) {
+ function modifyShaderForClippingPlanes(shader, clippingPlaneCollection) {
shader = ShaderSource.replaceMain(shader, 'gltf_clip_main');
+ shader += Model._getClippingFunction(clippingPlaneCollection) + '\n';
shader +=
- 'uniform int gltf_clippingPlanesLength; \n' +
- 'uniform bool gltf_clippingPlanesUnionRegions; \n' +
- 'uniform vec4 gltf_clippingPlanes[czm_maxClippingPlanes]; \n' +
+ 'uniform sampler2D gltf_clippingPlanes; \n' +
'uniform vec4 gltf_clippingPlanesEdgeStyle; \n' +
+ 'uniform mat4 gltf_clippingPlanesMatrix; \n' +
'void main() \n' +
'{ \n' +
' gltf_clip_main(); \n' +
- ' if (gltf_clippingPlanesLength > 0) \n' +
+ ' float clipDistance = clip(gl_FragCoord, gltf_clippingPlanes, gltf_clippingPlanesMatrix);' +
+ ' vec4 clippingPlanesEdgeColor = vec4(1.0); \n' +
+ ' clippingPlanesEdgeColor.rgb = gltf_clippingPlanesEdgeStyle.rgb; \n' +
+ ' float clippingPlanesEdgeWidth = gltf_clippingPlanesEdgeStyle.a; \n' +
+ ' if (clipDistance > 0.0 && clipDistance < clippingPlanesEdgeWidth) \n' +
' { \n' +
- ' float clipDistance; \n' +
- ' if (gltf_clippingPlanesUnionRegions) \n' +
- ' { \n' +
- ' clipDistance = czm_discardIfClippedWithUnion(gltf_clippingPlanes, gltf_clippingPlanesLength); \n' +
- ' } \n' +
- ' else \n' +
- ' { \n' +
- ' clipDistance = czm_discardIfClippedWithIntersect(gltf_clippingPlanes, gltf_clippingPlanesLength); \n' +
- ' } \n' +
- ' \n' +
- ' vec4 clippingPlanesEdgeColor = vec4(1.0); \n' +
- ' clippingPlanesEdgeColor.rgb = gltf_clippingPlanesEdgeStyle.rgb; \n' +
- ' float clippingPlanesEdgeWidth = gltf_clippingPlanesEdgeStyle.a; \n' +
- ' if (clipDistance > 0.0 && clipDistance < clippingPlanesEdgeWidth) \n' +
- ' { \n' +
- ' gl_FragColor = clippingPlanesEdgeColor; \n' +
- ' } \n' +
+ ' gl_FragColor = clippingPlanesEdgeColor;\n' +
' } \n' +
'} \n';
-
return shader;
}
- function updateSilhouette(model, frameState) {
+ function updateSilhouette(model, frameState, force) {
// Generate silhouette commands when the silhouette size is greater than 0.0 and the alpha is greater than 0.0
// There are two silhouette commands:
// 1. silhouetteModelCommand : render model normally while enabling stencil mask
@@ -3787,25 +3900,16 @@ define([
model._colorPreviousAlpha = model.color.alpha;
model._silhouetteColorPreviousAlpha = model.silhouetteColor.alpha;
- if (dirty) {
+ if (dirty || force) {
createSilhouetteCommands(model, frameState);
}
}
- function updateClippingPlanes(model) {
- var clippingPlanes = model.clippingPlanes;
- var length = 0;
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
- length = clippingPlanes.length;
- }
-
- var packedPlanes = model._packedClippingPlanes;
- var packedLength = packedPlanes.length;
- if (packedLength !== length) {
- packedPlanes.length = length;
-
- for (var i = packedLength; i < length; ++i) {
- packedPlanes[i] = new Cartesian4();
+ function updateClippingPlanes(model, frameState) {
+ var clippingPlanes = model._clippingPlanes;
+ if (defined(clippingPlanes) && clippingPlanes.owner === model) {
+ if (clippingPlanes.enabled) {
+ clippingPlanes.update(frameState);
}
}
}
@@ -4037,7 +4141,7 @@ define([
// Use renderer resources from cache instead of loading/creating them?
var cachedRendererResources;
var cacheKey = this.cacheKey;
- if (defined(cacheKey)) {
+ if (defined(cacheKey)) { // cache key given? this model will pull from or contribute to context level cache
context.cache.modelRendererResourceCache = defaultValue(context.cache.modelRendererResourceCache, {});
var modelCaches = context.cache.modelRendererResourceCache;
@@ -4057,7 +4161,7 @@ define([
modelCaches[this.cacheKey] = cachedRendererResources;
}
this._cachedRendererResources = cachedRendererResources;
- } else {
+ } else { // cache key not given? this model doesn't care about context level cache at all. Cache is here to simplify freeing on destroy.
cachedRendererResources = new CachedRendererResources(context);
cachedRendererResources.count = 1;
this._cachedRendererResources = cachedRendererResources;
@@ -4099,7 +4203,8 @@ define([
// Transition from LOADING -> LOADED once resources are downloaded and created.
// Textures may continue to stream in while in the LOADED state.
if (loadResources.pendingBufferLoads === 0) {
- if (!this._updatedGltfVersion) {
+ if (!loadResources.initialized) {
+ // glTF pipeline updates
var options = {
optimizeForCesium: true,
addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders
@@ -4111,6 +4216,19 @@ define([
addDefaults(this.gltf);
processModelMaterialsCommon(this.gltf, options);
processPbrMetallicRoughness(this.gltf, options);
+
+ // Start draco decoding
+ DracoLoader.parse(this);
+
+ loadResources.initialized = true;
+ }
+
+ if (!loadResources.finishedDecoding()) {
+ DracoLoader.decode(this, context)
+ .otherwise(getFailedLoadFunction(this, 'model', this.basePath));
+ }
+
+ if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
// We do this after to make sure that the ids don't change
addBuffersToLoadResources(this);
@@ -4126,12 +4244,16 @@ define([
this._boundingSphere = computeBoundingSphere(this);
this._initialRadius = this._boundingSphere.radius;
- this._updatedGltfVersion = true;
+
+ loadResources.resourcesParsed = true;
}
- if (this._updatedGltfVersion && loadResources.pendingShaderLoads === 0) {
+
+ if (loadResources.resourcesParsed &&
+ loadResources.pendingShaderLoads === 0) {
createResources(this, frameState);
}
}
+
if (loadResources.finished() ||
(incrementallyLoadTextures && loadResources.finishedEverythingButTextureCreation())) {
this._state = ModelState.LOADED;
@@ -4223,11 +4345,6 @@ define([
}
}
- var clippingPlanes = this.clippingPlanes;
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
- Matrix4.multiply(context.uniformState.view3D, modelMatrix, this._modelViewMatrix);
- }
-
// Update modelMatrix throughout the graph as needed
if (animated || modelTransformChanged || justLoaded) {
updateNodeHierarchyModelMatrix(this, modelTransformChanged, justLoaded, frameState.mapProjection);
@@ -4247,9 +4364,32 @@ define([
updateWireframe(this);
updateShowBoundingVolume(this);
updateShadows(this);
- updateColor(this, frameState);
- updateSilhouette(this, frameState);
updateClippingPlanes(this, frameState);
+
+ // Regnerate shaders if ClippingPlaneCollection state changed or it was removed
+ var clippingPlanes = this._clippingPlanes;
+ var currentClippingPlanesState = 0;
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
+ Matrix4.multiply(context.uniformState.view3D, modelMatrix, this._modelViewMatrix);
+ currentClippingPlanesState = clippingPlanes.clippingPlanesState();
+ }
+
+ var shouldRegenerateShaders = this._clippingPlanesState !== currentClippingPlanesState;
+ this._clippingPlanesState = currentClippingPlanesState;
+
+ // Regenerate shaders if color shading changed from last update
+ var currentlyColorShadingEnabled = isColorShadingEnabled(this);
+ if (currentlyColorShadingEnabled !== this._colorShadingEnabled) {
+ this._colorShadingEnabled = currentlyColorShadingEnabled;
+ shouldRegenerateShaders = true;
+ }
+
+ if (shouldRegenerateShaders) {
+ regenerateShaders(this, frameState);
+ } else {
+ updateColor(this, frameState, false);
+ updateSilhouette(this, frameState, false);
+ }
}
if (justLoaded) {
@@ -4328,6 +4468,83 @@ define([
}
};
+ function destroyIfNotCached(rendererResources, cachedRendererResources) {
+ if (rendererResources.programs !== cachedRendererResources.programs) {
+ destroy(rendererResources.programs);
+ }
+ if (rendererResources.pickPrograms !== cachedRendererResources.pickPrograms) {
+ destroy(rendererResources.pickPrograms);
+ }
+ if (rendererResources.silhouettePrograms !== cachedRendererResources.silhouettePrograms) {
+ destroy(rendererResources.silhouettePrograms);
+ }
+ }
+
+ // Run from update iff:
+ // - everything is loaded
+ // - clipping planes state change OR color state set
+ // Run this from destructor after removing color state and clipping plane state
+ function regenerateShaders(model, frameState) {
+ // In regards to _cachedRendererResources:
+ // Fair to assume that this is data that should just never get modified due to clipping planes or model color.
+ // So if clipping planes or model color active:
+ // - delink _rendererResources.*programs and create new dictionaries.
+ // - do NOT destroy any programs - might be used by copies of the model or by might be needed in the future if clipping planes/model color is deactivated
+
+ // If clipping planes and model color inactive:
+ // - destroy _rendererResources.*programs
+ // - relink _rendererResources.*programs to _cachedRendererResources
+
+ // In both cases, need to mark commands as dirty, re-run derived commands (elsewhere)
+
+ var rendererResources = model._rendererResources;
+ var cachedRendererResources = model._cachedRendererResources;
+ destroyIfNotCached(rendererResources, cachedRendererResources);
+
+ if (isClippingEnabled(model) || isColorShadingEnabled(model)) {
+ rendererResources.programs = {};
+ rendererResources.pickPrograms = {};
+ rendererResources.silhouettePrograms = {};
+
+ var sourcePrograms = model._sourcePrograms;
+
+ ForEach.object(sourcePrograms, function(program, id) {
+ recreateProgram(id, model, frameState.context);
+ });
+ } else {
+ rendererResources.programs = cachedRendererResources.programs;
+ rendererResources.pickPrograms = cachedRendererResources.pickPrograms;
+ rendererResources.silhouettePrograms = cachedRendererResources.silhouettePrograms;
+ }
+
+ // Fix all the commands, marking them as dirty so everything that derives will re-derive
+ var rendererPrograms = rendererResources.programs;
+ var rendererPickPrograms = rendererResources.pickPrograms;
+
+ var nodeCommands = model._nodeCommands;
+ var commandCount = nodeCommands.length;
+ for (var i = 0; i < commandCount; ++i) {
+ var nodeCommand = nodeCommands[i];
+ var programId = nodeCommand.programId;
+
+ var renderProgram = rendererPrograms[programId];
+ var pickProgram = rendererPickPrograms[programId];
+
+ nodeCommand.command.shaderProgram = renderProgram;
+ nodeCommand.pickCommand.shaderProgram = pickProgram;
+ if (defined(nodeCommand.command2D)) {
+ nodeCommand.command2D.shaderProgram = renderProgram;
+ }
+ if (defined(nodeCommand.pickCommand2D)) {
+ nodeCommand.pickCommand2D.shaderProgram = pickProgram;
+ }
+ }
+
+ // Force update silhouette commands/shaders
+ updateColor(model, frameState, true);
+ updateSilhouette(model, frameState, true);
+ }
+
/**
* Returns true if this object was destroyed; otherwise, false.
* {s}
placeholder in the URL template.
* If this parameter is a single string, each character in the string is a subdomain. If it is
@@ -133,10 +135,10 @@ define([
// Use CRS with 1.3.0 and going forward.
// For GeographicTilingScheme, use CRS:84 vice EPSG:4326 to specify lon, lat (x, y) ordering for
// bbox requests.
- parameters.crs = options.tilingScheme instanceof WebMercatorTilingScheme ? 'EPSG:3857' : 'CRS:84';
+ parameters.crs = defaultValue(options.crs, options.tilingScheme instanceof WebMercatorTilingScheme ? 'EPSG:3857' : 'CRS:84');
} else {
// SRS for WMS 1.1.0 or 1.1.1.
- parameters.srs = options.tilingScheme instanceof WebMercatorTilingScheme ? 'EPSG:3857' : 'EPSG:4326';
+ parameters.srs = defaultValue(options.srs, options.tilingScheme instanceof WebMercatorTilingScheme ? 'EPSG:3857' : 'EPSG:4326');
}
resource.setQueryParameters(parameters, true);
diff --git a/Source/Scene/getClippingFunction.js b/Source/Scene/getClippingFunction.js
new file mode 100644
index 000000000000..495700e3eb87
--- /dev/null
+++ b/Source/Scene/getClippingFunction.js
@@ -0,0 +1,168 @@
+define([
+ '../Core/Check',
+ '../Renderer/PixelDatatype',
+ './getUnpackFloatFunction'
+ ], function(
+ Check,
+ PixelDatatype,
+ getUnpackFloatFunction) {
+ 'use strict';
+
+ /**
+ * Gets the glsl functions needed to retrieve clipping planes from a ClippingPlaneCollection's texture.
+ *
+ * @param {ClippingPlaneCollection} clippingPlaneCollection ClippingPlaneCollection with a defined texture.
+ * @returns {String} A string containing glsl functions for retrieving clipping planes.
+ * @private
+ */
+ function getClippingFunction(clippingPlaneCollection) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object('clippingPlaneCollection', clippingPlaneCollection);
+ //>>includeEnd('debug');
+ var unionClippingRegions = clippingPlaneCollection.unionClippingRegions;
+ var clippingPlanesLength = clippingPlaneCollection.length;
+ var texture = clippingPlaneCollection.texture;
+ var usingFloatTexture = texture.pixelDatatype === PixelDatatype.FLOAT;
+ var width = texture.width;
+ var height = texture.height;
+
+ var functions = usingFloatTexture ? getClippingPlaneFloat(width, height) : getClippingPlaneUint8(width, height);
+ functions += '\n';
+ functions += unionClippingRegions ? clippingFunctionUnion(usingFloatTexture, clippingPlanesLength) : clippingFunctionIntersect(usingFloatTexture, clippingPlanesLength);
+ return functions;
+ }
+
+ function clippingFunctionUnion(usingFloatTexture, clippingPlanesLength) {
+ var functionString =
+ 'float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix)\n' +
+ '{\n' +
+ ' vec4 position = czm_windowToEyeCoordinates(fragCoord);\n' +
+ ' vec3 clipNormal = vec3(0.0);\n' +
+ ' vec3 clipPosition = vec3(0.0);\n' +
+ ' float clipAmount = 0.0;\n' +
+ ' float pixelWidth = czm_metersPerPixel(position);\n' +
+ ' bool breakAndDiscard = false;\n' +
+
+ ' for (int i = 0; i < ' + clippingPlanesLength + '; ++i)\n' +
+ ' {\n' +
+ ' vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);\n' +
+
+ ' clipNormal = clippingPlane.xyz;\n' +
+ ' clipPosition = -clippingPlane.w * clipNormal;\n' +
+
+ ' float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;\n' +
+ ' clipAmount = max(amount, clipAmount);\n' +
+
+ ' if (amount <= 0.0)\n' +
+ ' {\n' +
+ ' breakAndDiscard = true;\n' +
+ ' break;\n' + // HLSL compiler bug if we discard here: https://bugs.chromium.org/p/angleproject/issues/detail?id=1945#c6
+ ' }\n' +
+ ' }\n' +
+
+ ' if (breakAndDiscard) {\n' +
+ ' discard;\n' +
+ ' }\n' +
+ ' return clipAmount;\n' +
+ '}\n';
+ return functionString;
+ }
+
+ function clippingFunctionIntersect(usingFloatTexture, clippingPlanesLength) {
+ var functionString =
+ 'float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix)\n' +
+ '{\n' +
+ ' bool clipped = true;\n' +
+ ' vec4 position = czm_windowToEyeCoordinates(fragCoord);\n' +
+ ' vec3 clipNormal = vec3(0.0);\n' +
+ ' vec3 clipPosition = vec3(0.0);\n' +
+ ' float clipAmount = 0.0;\n' +
+ ' float pixelWidth = czm_metersPerPixel(position);\n' +
+
+ ' for (int i = 0; i < ' + clippingPlanesLength + '; ++i)\n' +
+ ' {\n' +
+ ' vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);\n' +
+
+ ' clipNormal = clippingPlane.xyz;\n' +
+ ' clipPosition = -clippingPlane.w * clipNormal;\n' +
+
+ ' float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;\n' +
+ ' clipAmount = max(amount, clipAmount);\n' +
+
+ ' clipped = clipped && (amount <= 0.0);\n' +
+ ' }\n' +
+
+ ' if (clipped)\n' +
+ ' {\n' +
+ ' discard;\n' +
+ ' }\n' +
+
+ ' return clipAmount;\n' +
+ '}\n';
+ return functionString;
+ }
+
+ function getClippingPlaneFloat(width, height) {
+ var pixelWidth = 1.0 / width;
+ var pixelHeight = 1.0 / height;
+
+ var pixelWidthString = pixelWidth + '';
+ if (pixelWidthString.indexOf('.') === -1) {
+ pixelWidthString += '.0';
+ }
+ var pixelHeightString = pixelHeight + '';
+ if (pixelHeightString.indexOf('.' === -1)) {
+ pixelHeightString += '.0';
+ }
+
+ var functionString =
+ 'vec4 getClippingPlane(sampler2D packedClippingPlanes, int clippingPlaneNumber, mat4 transform)\n' +
+ '{\n' +
+ ' int pixY = clippingPlaneNumber / ' + width + ';\n' +
+ ' int pixX = clippingPlaneNumber - (pixY * ' + width + ');\n' +
+ ' float u = (float(pixX) + 0.5) * ' + pixelWidthString + ';\n' + // sample from center of pixel
+ ' float v = (float(pixY) + 0.5) * ' + pixelHeightString + ';\n' +
+ ' vec4 plane = texture2D(packedClippingPlanes, vec2(u, v));\n' +
+ ' return czm_transformPlane(transform, plane);\n' +
+ '}\n';
+ return functionString;
+ }
+
+ function getClippingPlaneUint8(width, height) {
+ var pixelWidth = 1.0 / width;
+ var pixelHeight = 1.0 / height;
+
+ var pixelWidthString = pixelWidth + '';
+ if (pixelWidthString.indexOf('.') === -1) {
+ pixelWidthString += '.0';
+ }
+ var pixelHeightString = pixelHeight + '';
+ if (pixelHeightString.indexOf('.' === -1)) {
+ pixelHeightString += '.0';
+ }
+
+ var functionString =
+ getUnpackFloatFunction('unpackFloatDistance') +
+ '\n' +
+ 'vec4 getClippingPlane(sampler2D packedClippingPlanes, int clippingPlaneNumber, mat4 transform)\n' +
+ '{\n' +
+ ' int clippingPlaneStartIndex = clippingPlaneNumber * 2;\n' + // clipping planes are two pixels each
+ ' int pixY = clippingPlaneStartIndex / ' + width + ';\n' +
+ ' int pixX = clippingPlaneStartIndex - (pixY * ' + width + ');\n' +
+ ' float u = (float(pixX) + 0.5) * ' + pixelWidthString + ';\n' + // sample from center of pixel
+ ' float v = (float(pixY) + 0.5) * ' + pixelHeightString + ';\n' +
+
+ ' vec4 oct32 = texture2D(packedClippingPlanes, vec2(u, v)) * 255.0;\n' +
+ ' vec2 oct = vec2(oct32.x * 256.0 + oct32.y, oct32.z * 256.0 + oct32.w);\n' +
+
+ ' vec4 plane;\n' +
+ ' plane.xyz = czm_octDecode(oct, 65535.0);\n' +
+ ' plane.w = unpackFloatDistance(texture2D(packedClippingPlanes, vec2(u + ' + pixelWidthString + ', v)));\n' +
+
+ ' return czm_transformPlane(transform, plane);\n' +
+ '}\n';
+ return functionString;
+ }
+
+ return getClippingFunction;
+});
diff --git a/Source/Scene/getUnpackFloatFunction.js b/Source/Scene/getUnpackFloatFunction.js
new file mode 100644
index 000000000000..dae8fb286cab
--- /dev/null
+++ b/Source/Scene/getUnpackFloatFunction.js
@@ -0,0 +1,42 @@
+define([
+ '../Core/defined'
+ ], function(
+ defined) {
+ 'use strict';
+
+ var SHIFT_RIGHT_8 = 1.0 / 256.0;
+ var SHIFT_RIGHT_16 = 1.0 / 65536.0;
+ var SHIFT_RIGHT_24 = 1.0 / 16777216.0;
+
+ var BIAS = 38.0;
+
+ /**
+ * Gets a glsl function that takes a vec4 representing a float packed to Uint8 RGBA and returns the unpacked float.
+ *
+ * @param {String} [functionName='unpackFloat'] An optional name for the glsl function.
+ * @returns {String} A string containing a glsl function that takes a vec4 and returns a float.
+ * @private
+ * @see Cartesian4#packFloat
+ */
+ function getUnpackFloatFunction(functionName) {
+ if (!defined(functionName)) {
+ functionName = 'unpackFloat';
+ }
+ return 'float ' + functionName + '(vec4 value) \n' +
+ '{ \n' +
+ ' value *= 255.0; \n' +
+ ' float temp = value.w / 2.0; \n' +
+ ' float exponent = floor(temp); \n' +
+ ' float sign = (temp - exponent) * 2.0; \n' +
+ ' exponent = exponent - float(' + BIAS + '); \n' +
+ ' sign = sign * 2.0 - 1.0; \n' +
+ ' sign = -sign; \n' +
+ ' float unpacked = sign * value.x * float(' + SHIFT_RIGHT_8 + '); \n' +
+ ' unpacked += sign * value.y * float(' + SHIFT_RIGHT_16 + '); \n' +
+ ' unpacked += sign * value.z * float(' + SHIFT_RIGHT_24 + '); \n' +
+ ' return unpacked * pow(10.0, exponent); \n' +
+ '} \n';
+ }
+
+ return getUnpackFloatFunction;
+});
diff --git a/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl b/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl
deleted file mode 100644
index 30c377df1668..000000000000
--- a/Source/Shaders/Builtin/Constants/maxClippingPlanes.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * The maximum amount of planes that can be clipped by czm_clipPlanes.
- *
- * @name czm_maxClippingPlanes
- * @glslConstant
- * @see czm_clipPlanes
- */
-const int czm_maxClippingPlanes = 6;
diff --git a/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl b/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl
deleted file mode 100644
index 987dd8d354c8..000000000000
--- a/Source/Shaders/Builtin/Functions/discardIfClippedWithIntersect.glsl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Clip a fragment by an array of clipping planes. Clipping plane regions are joined by the intersect operation, so
- * a fragment must be clipped by all of the planes to be discarded.
- *
- * @name czm_discardIfClippedWithIntersect
- * @glslFunction
- *
- * @param {vec4[]} clippingPlanes The array of planes used to clip, defined in eyespace.
- * @param {int} clippingPlanesLength The number of planes in the array of clipping planes.
- * @returns {float} The distance away from a clipped fragment, in eyespace
- */
-float czm_discardIfClippedWithIntersect(vec4 clippingPlanes[czm_maxClippingPlanes], int clippingPlanesLength)
-{
- if (clippingPlanesLength > 0)
- {
- bool clipped = true;
- vec4 position = czm_windowToEyeCoordinates(gl_FragCoord);
- vec3 clipNormal = vec3(0.0);
- vec3 clipPosition = vec3(0.0);
- float clipAmount = 0.0;
- float pixelWidth = czm_metersPerPixel(position);
-
- for (int i = 0; i < czm_maxClippingPlanes; ++i)
- {
- if (i == clippingPlanesLength)
- {
- break;
- }
-
- clipNormal = clippingPlanes[i].xyz;
- clipPosition = -clippingPlanes[i].w * clipNormal;
-
- float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;
- clipAmount = max(amount, clipAmount);
-
- clipped = clipped && (amount <= 0.0);
- }
-
- if (clipped)
- {
- discard;
- }
-
- return clipAmount;
- }
-
- return 0.0;
-}
diff --git a/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl b/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl
deleted file mode 100644
index ae6110f8346f..000000000000
--- a/Source/Shaders/Builtin/Functions/discardIfClippedWithUnion.glsl
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Clip a fragment by an array of clipping planes. Clipping plane regions are joined with the union operation,
- * therefore if a fragment is clipped by any of the planes, it is discarded.
- *
- * @name czm_discardIfClippedWithUnion
- * @glslFunction
- *
- * @param {vec4[]} clippingPlanes The array of planes used to clip, defined in eyespace.
- * @param {int} clippingPlanesLength The number of planes in the array of clipping planes.
- * @returns {float} The distance away from a clipped fragment, in eyespace
- */
-float czm_discardIfClippedWithUnion(vec4 clippingPlanes[czm_maxClippingPlanes], int clippingPlanesLength)
-{
- if (clippingPlanesLength > 0)
- {
- vec4 position = czm_windowToEyeCoordinates(gl_FragCoord);
- vec3 clipNormal = vec3(0.0);
- vec3 clipPosition = vec3(0.0);
- float clipAmount = 0.0;
- float pixelWidth = czm_metersPerPixel(position);
-
- for (int i = 0; i < czm_maxClippingPlanes; ++i)
- {
- if (i == clippingPlanesLength)
- {
- break;
- }
-
- clipNormal = clippingPlanes[i].xyz;
- clipPosition = -clippingPlanes[i].w * clipNormal;
-
- float amount = dot(clipNormal, (position.xyz - clipPosition)) / pixelWidth;
- clipAmount = max(amount, clipAmount);
-
- if (amount <= 0.0)
- {
- discard;
- }
- }
-
- return clipAmount;
- }
-
- return 0.0;
-}
diff --git a/Source/Shaders/Builtin/Functions/metersPerPixel.glsl b/Source/Shaders/Builtin/Functions/metersPerPixel.glsl
index 953008963e28..f6066d21e0b5 100644
--- a/Source/Shaders/Builtin/Functions/metersPerPixel.glsl
+++ b/Source/Shaders/Builtin/Functions/metersPerPixel.glsl
@@ -1,6 +1,6 @@
/**
* Computes the size of a pixel in meters at a distance from the eye.
-
+
* @name czm_metersPerPixel
* @glslFunction
*
@@ -14,13 +14,13 @@ float czm_metersPerPixel(vec4 positionEC)
float height = czm_viewport.w;
float pixelWidth;
float pixelHeight;
-
+
float top = czm_frustumPlanes.x;
float bottom = czm_frustumPlanes.y;
float left = czm_frustumPlanes.z;
float right = czm_frustumPlanes.w;
-
- if (czm_sceneMode == czm_sceneMode2D)
+
+ if (czm_sceneMode == czm_sceneMode2D || czm_orthographicIn3D == 1.0)
{
float frustumWidth = right - left;
float frustumHeight = top - bottom;
diff --git a/Source/Shaders/Builtin/Functions/octDecode.glsl b/Source/Shaders/Builtin/Functions/octDecode.glsl
index ce4df362da12..98b2736f706a 100644
--- a/Source/Shaders/Builtin/Functions/octDecode.glsl
+++ b/Source/Shaders/Builtin/Functions/octDecode.glsl
@@ -28,7 +28,7 @@
* Decodes a unit-length vector in 'oct' encoding to a normalized 3-component Cartesian vector.
* The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors",
* Cigolle et al 2014: http://jcgt.org/published/0003/02/01/
- *
+ *
* @name czm_octDecode
* @param {vec2} encoded The oct-encoded, unit-length vector
* @returns {vec3} The decoded and normalized vector
@@ -42,7 +42,7 @@
* Decodes a unit-length vector in 'oct' encoding packed into a floating-point number to a normalized 3-component Cartesian vector.
* The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors",
* Cigolle et al 2014: http://jcgt.org/published/0003/02/01/
- *
+ *
* @name czm_octDecode
* @param {float} encoded The oct-encoded, unit-length vector
* @returns {vec3} The decoded and normalized vector
@@ -54,12 +54,12 @@
float y = (temp - x) * 256.0;
return czm_octDecode(vec2(x, y));
}
-
+
/**
* Decodes three unit-length vectors in 'oct' encoding packed into two floating-point numbers to normalized 3-component Cartesian vectors.
* The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors",
* Cigolle et al 2014: http://jcgt.org/published/0003/02/01/
- *
+ *
* @name czm_octDecode
* @param {vec2} encoded The packed oct-encoded, unit-length vectors.
* @param {vec3} vector1 One decoded and normalized vector.
@@ -80,4 +80,4 @@
vector2 = czm_octDecode(encodedFloat2);
vector3 = czm_octDecode(vec2(x, y));
}
-
+
diff --git a/Source/Shaders/Builtin/Functions/transformPlane.glsl b/Source/Shaders/Builtin/Functions/transformPlane.glsl
new file mode 100644
index 000000000000..3f0412c891cb
--- /dev/null
+++ b/Source/Shaders/Builtin/Functions/transformPlane.glsl
@@ -0,0 +1,8 @@
+vec4 czm_transformPlane(mat4 transform, vec4 clippingPlane) {
+ vec3 transformedDirection = normalize((transform * vec4(clippingPlane.xyz, 0.0)).xyz);
+ vec3 transformedPosition = (transform * vec4(clippingPlane.xyz * -clippingPlane.w, 1.0)).xyz;
+ vec4 transformedPlane;
+ transformedPlane.xyz = transformedDirection;
+ transformedPlane.w = -dot(transformedDirection, transformedPosition);
+ return transformedPlane;
+}
diff --git a/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl b/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl
index f429c26875ec..91bd5e3164f6 100644
--- a/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl
+++ b/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl
@@ -31,9 +31,12 @@ vec4 czm_windowToEyeCoordinates(vec4 fragmentCoordinate)
vec4 q = vec4(x, y, z, 1.0);
q /= fragmentCoordinate.w;
- if (czm_inverseProjection != mat4(0.0)) {
+ if (!(czm_inverseProjection == mat4(0.0))) // IE and Edge sometimes do something weird with != between mat4s
+ {
q = czm_inverseProjection * q;
- } else {
+ }
+ else
+ {
float top = czm_frustumPlanes.x;
float bottom = czm_frustumPlanes.y;
float left = czm_frustumPlanes.z;
diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl
index f41b6eb34b31..bf64b95bcdf5 100644
--- a/Source/Shaders/GlobeFS.glsl
+++ b/Source/Shaders/GlobeFS.glsl
@@ -52,8 +52,8 @@ uniform vec2 u_lightingFadeDistance;
#endif
#ifdef ENABLE_CLIPPING_PLANES
-uniform int u_clippingPlanesLength;
-uniform vec4 u_clippingPlanes[czm_maxClippingPlanes];
+uniform sampler2D u_clippingPlanes;
+uniform mat4 u_clippingPlanesMatrix;
uniform vec4 u_clippingPlanesEdgeStyle;
#endif
@@ -156,11 +156,7 @@ vec4 computeWaterColor(vec3 positionEyeCoordinates, vec2 textureCoordinates, mat
void main()
{
#ifdef ENABLE_CLIPPING_PLANES
- #ifdef UNION_CLIPPING_REGIONS
- float clipDistance = czm_discardIfClippedWithUnion(u_clippingPlanes, u_clippingPlanesLength);
- #else
- float clipDistance = czm_discardIfClippedWithIntersect(u_clippingPlanes, u_clippingPlanesLength);
- #endif
+ float clipDistance = clip(gl_FragCoord, u_clippingPlanes, u_clippingPlanesMatrix);
#endif
// The clamp below works around an apparent bug in Chrome Canary v23.0.1241.0
diff --git a/Source/ThirdParty/draco-decoder-gltf.js b/Source/ThirdParty/draco-decoder-gltf.js
new file mode 100644
index 000000000000..bf59515f91c6
--- /dev/null
+++ b/Source/ThirdParty/draco-decoder-gltf.js
@@ -0,0 +1,27 @@
+define([], function() {
+ DracoDecoderModule = {};
+ var Module = DracoDecoderModule; // included code may refer to Module (e.g. from file packager), so alias it
+
+var isRuntimeInitialized=false;var isModuleParsed=false;Module["onRuntimeInitialized"]=(function(){isRuntimeInitialized=true;if(isModuleParsed){if(typeof Module["onModuleLoaded"]==="function"){Module["onModuleLoaded"](Module)}}});Module["onModuleParsed"]=(function(){isModuleParsed=true;if(isRuntimeInitialized){if(typeof Module["onModuleLoaded"]==="function"){Module["onModuleLoaded"](Module)}}});function isVersionSupported(versionString){if(typeof versionString!=="string")return false;const version=versionString.split(".");if(version.length<2||version.length>3)return false;if(version[0]==1&&version[1]>=0&&version[1]<=2)return true;if(version[0]!=0||version[1]>10)return false;return true}Module["isVersionSupported"]=isVersionSupported;var Module;if(!Module)Module=(typeof DracoDecoderModule!=="undefined"?DracoDecoderModule:null)||{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=console.log;if(!Module["printErr"])Module["printErr"]=console.warn;var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;ret=tryParseAsDataURI(filename);if(!ret){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename)}return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=function shell_read(f){var data=tryParseAsDataURI(f);if(data){return intArrayToString(data)}return read(f)}}else{Module["read"]=function shell_read(){throw"no read() available"}}Module["readBinary"]=function readBinary(f){var data;data=tryParseAsDataURI(f);if(data){return data}if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function shell_print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function shell_printErr(x){console.warn(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw new Error("Unknown runtime environment. Where are we?")}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}if(!Module["quit"]){Module["quit"]=(function(status,toThrow){throw toThrow})}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var Runtime={setTempRet0:(function(value){tempRet0=value;return value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i>>0)):0)?(E=n+i|0,E=h[E>>0]|h[E+1>>0]<<8|h[E+2>>0]<<16|h[E+3>>0]<<24,A=o,f[A>>2]=p,f[A+4>>2]=q,wh(a,E)|0,im(B),f[r>>2]=a,f[r+4>>2]=0,f[C>>2]=f[r>>2],f[C+4>>2]=f[r+4>>2],ld(B,c,C)|0):0){E=1;u=D;return E|0}E=0;u=D;return E|0}case 1:{a:do if((m|0)>(e|0)|(m|0)==(e|0)&l>>>0>d>>>0){i=b[n+d>>0]|0;g=Hl(j|0,k|0,2,0)|0;E=o;f[E>>2]=g;f[E+4>>2]=I;if((i&255)>6){f[s>>2]=i&255;nl(4934,s)|0;break}d=Hl(j|0,k|0,6,0)|0;e=I;if(!((m|0)<(e|0)|(m|0)==(e|0)&l>>>0 >>(o>>>0))&j|l< >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0 >>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;q=Hl(g|0,j|0,4,0)|0;p=I;if((i|0)<(p|0)|(i|0)==(p|0)&e>>>0>>0)r=x;else r=(x>>>0)%(s>>>0)|0;else r=x&q;j=f[(f[a>>2]|0)+(r<<2)>>2]|0;if((j|0)!=0?(e=f[j>>2]|0,(e|0)!=0):0){p=(v|0)==0;if(k){if(p){d=e;while(1){w=f[d+4>>2]|0;if(!((w|0)==(x|0)|(w&q|0)==(r|0))){d=r;break a}w=b[d+8+11>>0]|0;if(!((w<<24>>24<0?f[d+12>>2]|0:w&255)|0)){j=d;break}d=f[d>>2]|0;if(!d){d=r;break a}}a=j+20|0;return a|0}else j=e;b:while(1){o=f[j+4>>2]|0;if(!((o|0)==(x|0)|(o&q|0)==(r|0))){d=r;break a}k=j+8|0;m=b[k+11>>0]|0;o=m<<24>>24<0;m=m&255;do if(((o?f[j+12>>2]|0:m)|0)==(v|0)){l=f[k>>2]|0;if(o)if(!(ij(l,w,v)|0)){z=63;break b}else break;if((l&255)<<24>>24==(b[w>>0]|0)){l=w;do{m=m+-1|0;k=k+1|0;if(!m){z=63;break b}l=l+1|0}while((b[k>>0]|0)==(b[l>>0]|0))}}while(0);j=f[j>>2]|0;if(!j){d=r;break a}}if((z|0)==63){a=j+20|0;return a|0}}if(p){while(1){d=f[e+4>>2]|0;if((d|0)!=(x|0)){if(d>>>0>=s>>>0)d=(d>>>0)%(s>>>0)|0;if((d|0)!=(r|0)){d=r;break a}}w=b[e+8+11>>0]|0;if(!((w<<24>>24<0?f[e+12>>2]|0:w&255)|0)){j=e;break}e=f[e>>2]|0;if(!e){d=r;break a}}a=j+20|0;return a|0}c:while(1){j=f[e+4>>2]|0;if((j|0)!=(x|0)){if(j>>>0>=s>>>0)j=(j>>>0)%(s>>>0)|0;if((j|0)!=(r|0)){d=r;break a}}j=e+8|0;l=b[j+11>>0]|0;m=l<<24>>24<0;l=l&255;do if(((m?f[e+12>>2]|0:l)|0)==(v|0)){k=f[j>>2]|0;if(m)if(!(ij(k,w,v)|0)){j=e;z=63;break c}else break;if((k&255)<<24>>24==(b[w>>0]|0)){k=w;do{l=l+-1|0;j=j+1|0;if(!l){j=e;z=63;break c}k=k+1|0}while((b[j>>0]|0)==(b[k>>0]|0))}}while(0);e=f[e>>2]|0;if(!e){d=r;break a}}if((z|0)==63){a=j+20|0;return a|0}}else d=r}else d=0;while(0);l=Rk(24)|0;lh(l+8|0,c);f[l+20>>2]=0;f[l+4>>2]=x;f[l>>2]=0;k=a+12|0;i=$(((f[k>>2]|0)+1|0)>>>0);A=$(s>>>0);g=$(n[a+16>>2]);do if(u|i>$(A*g)){d=(s>>>0<3|(s+-1&s|0)!=0)&1|s<<1;e=~~$(W($(i/g)))>>>0;Zf(a,d>>>0>>0;h=l?i:q;if((h|0)!=0?(k=ij(r?f[g>>2]|0:g,m?f[j>>2]|0:j,h)|0,(k|0)!=0):0){if((k|0)<0)break}else u=4;if((u|0)==4?q>>>0>>0:0)break;h=q>>>0>>0?q:i;if((h|0)!=0?(n=ij(m?f[j>>2]|0:j,r?f[g>>2]|0:g,h)|0,(n|0)!=0):0){if((n|0)>=0)u=36}else u=20;if((u|0)==20?!l:0)u=36;if((u|0)==36){f[d>>2]=c;f[e>>2]=c;d=e;return d|0}m=t+4|0;h=f[m>>2]|0;if(!h){i=t+8|0;h=f[i>>2]|0;if((f[h>>2]|0)!=(t|0))do{p=f[i>>2]|0;i=p+8|0;h=f[i>>2]|0}while((f[h>>2]|0)!=(p|0))}else while(1){i=f[h>>2]|0;if(!i)break;else h=i}do if((h|0)!=(o|0)){j=h+16|0;k=b[j+11>>0]|0;l=k<<24>>24<0;k=l?f[h+20>>2]|0:k&255;i=k>>>0
>>0?k:q;if((i|0)!=0?(s=ij(r?f[g>>2]|0:g,l?f[j>>2]|0:j,i)|0,(s|0)!=0):0){if((s|0)<0)break}else u=30;if((u|0)==30?q>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)i=k;else{g=(f[c>>2]|0)+g|0;g=h[g>>0]|h[g+1>>0]<<8|h[g+2>>0]<<16|h[g+3>>0]<<24;b[a>>0]=g;b[a+1>>0]=g>>8;b[a+2>>0]=g>>16;b[a+3>>0]=g>>24;g=l;g=Hl(f[g>>2]|0,f[g+4>>2]|0,4,0)|0;j=I;e=l;f[e>>2]=g;f[e+4>>2]=j;e=i;i=f[e+4>>2]|0;e=f[e>>2]|0}k=a+4|0;r=Hl(g|0,j|0,4,0)|0;q=I;if((i|0)<(q|0)|(i|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(oe(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+32|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+52|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+72|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;f[m>>2]=f[d>>2];f[n>>2]=f[m>>2];ib(a,q,n);q=1;u=o;return q|0}function td(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,g=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;o=u;u=u+16|0;n=o+4|0;m=o;i=c+8|0;k=i;e=f[k>>2]|0;k=f[k+4>>2]|0;l=c+16|0;j=l;g=f[j>>2]|0;j=f[j+4>>2]|0;p=Hl(g|0,j|0,4,0)|0;q=I;if((k|0)<(q|0)|(k|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(oe(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+32|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+52|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+72|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;f[m>>2]=f[d>>2];f[n>>2]=f[m>>2];gb(a,q,n);q=1;u=o;return q|0}function ud(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,g=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;o=u;u=u+16|0;n=o+4|0;m=o;i=c+8|0;k=i;e=f[k>>2]|0;k=f[k+4>>2]|0;l=c+16|0;j=l;g=f[j>>2]|0;j=f[j+4>>2]|0;p=Hl(g|0,j|0,4,0)|0;q=I;if((k|0)<(q|0)|(k|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(nd(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+28|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+48|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+68|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;f[m>>2]=f[d>>2];f[n>>2]=f[m>>2];ub(a,q,n);q=1;u=o;return q|0}function vd(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,g=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;o=u;u=u+16|0;n=o+4|0;m=o;i=c+8|0;k=i;e=f[k>>2]|0;k=f[k+4>>2]|0;l=c+16|0;j=l;g=f[j>>2]|0;j=f[j+4>>2]|0;p=Hl(g|0,j|0,4,0)|0;q=I;if((k|0)<(q|0)|(k|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(nd(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+28|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+48|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+68|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;f[m>>2]=f[d>>2];f[n>>2]=f[m>>2];tb(a,q,n);q=1;u=o;return q|0}function wd(a,c){a=a|0;c=c|0;var d=0,e=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=f[a+8>>2]|0;k=a+76|0;d=f[k>>2]|0;m=f[d+80>>2]|0;r=c+84|0;b[r>>0]=0;j=c+68|0;h=c+72|0;g=f[h>>2]|0;e=f[j>>2]|0;l=g-e>>2;if(m>>>0<=l>>>0){if(m>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(oe(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+32|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+52|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+72|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;c=d;d=f[c+4>>2]|0;p=m;f[p>>2]=f[c>>2];f[p+4>>2]=d;f[n>>2]=f[m>>2];f[n+4>>2]=f[m+4>>2];hb(a,q,n);q=1;u=o;return q|0}function yd(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,g=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;o=u;u=u+16|0;n=o+8|0;m=o;i=c+8|0;k=i;e=f[k>>2]|0;k=f[k+4>>2]|0;l=c+16|0;j=l;g=f[j>>2]|0;j=f[j+4>>2]|0;p=Hl(g|0,j|0,4,0)|0;q=I;if((k|0)<(q|0)|(k|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(oe(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+32|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+52|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+72|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;c=d;d=f[c+4>>2]|0;p=m;f[p>>2]=f[c>>2];f[p+4>>2]=d;f[n>>2]=f[m>>2];f[n+4>>2]=f[m+4>>2];fb(a,q,n);q=1;u=o;return q|0}function zd(a,c){a=a|0;c=c|0;var d=0,e=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;q=f[a+8>>2]|0;k=a+112|0;d=f[k>>2]|0;m=f[d+80>>2]|0;r=c+84|0;b[r>>0]=0;j=c+68|0;h=c+72|0;g=f[h>>2]|0;e=f[j>>2]|0;l=g-e>>2;if(m>>>0<=l>>>0){if(m>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(nd(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+28|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+48|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+68|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;c=d;d=f[c+4>>2]|0;p=m;f[p>>2]=f[c>>2];f[p+4>>2]=d;f[n>>2]=f[m>>2];f[n+4>>2]=f[m+4>>2];sb(a,q,n);q=1;u=o;return q|0}function Bd(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,g=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;o=u;u=u+16|0;n=o+8|0;m=o;i=c+8|0;k=i;e=f[k>>2]|0;k=f[k+4>>2]|0;l=c+16|0;j=l;g=f[j>>2]|0;j=f[j+4>>2]|0;p=Hl(g|0,j|0,4,0)|0;q=I;if((k|0)<(q|0)|(k|0)==(q|0)&e>>>0
>>0)e=f[k>>2]|0;else{e=(f[c>>2]|0)+g|0;e=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[k>>0]=e;b[k+1>>0]=e>>8;b[k+2>>0]=e>>16;b[k+3>>0]=e>>24;p=l;p=Hl(f[p>>2]|0,f[p+4>>2]|0,4,0)|0;q=l;f[q>>2]=p;f[q+4>>2]=I}if(!e){q=1;u=o;return q|0}if(!(nd(a+12|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+28|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+48|0,c)|0)){q=0;u=o;return q|0}if(!(oe(a+68|0,c)|0)){q=0;u=o;return q|0}q=f[k>>2]|0;c=d;d=f[c+4>>2]|0;p=m;f[p>>2]=f[c>>2];f[p+4>>2]=d;f[n>>2]=f[m>>2];f[n+4>>2]=f[m+4>>2];rb(a,q,n);q=1;u=o;return q|0}function Cd(a,c){a=a|0;c=c|0;var d=0,e=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;m=u;u=u+16|0;k=m;if(!(Wb(a,c)|0)){a=0;u=m;return a|0}j=Na[f[(f[a>>2]|0)+24>>2]&127](a)|0;l=a+36|0;h=a+40|0;d=f[h>>2]|0;e=f[l>>2]|0;g=d-e>>2;if(j>>>0<=g>>>0){if(j>>>0
>>0){a=0;return a|0}ef(f[a>>2]|0,(f[b>>2]|0)+g|0,o|0)|0;q=r;q=Hl(f[q>>2]|0,f[q+4>>2]|0,o|0,0)|0;b=r;f[b>>2]=q;f[b+4>>2]=I;f[t>>2]=f[a>>2];f[s>>2]=0;a=1;return a|0}function pe(a,b,c,d){a=a|0;b=$(b);c=$(c);d=d|0;var e=La,f=La,g=0.0,h=La,i=La,j=0.0,k=0.0,l=0.0,m=0.0;if(!(b>=$(0.0)))ra(9337,9190,191,9351);if(!(c>=$(0.0)))ra(9380,9190,192,9351);if(!(b<=$(1.0)))ra(9394,9190,193,9351);if(!(c<=$(1.0)))ra(9408,9190,194,9351);f=$(b+c);e=$(b-c);if(!(e<=$(.5))|(!(e>=$(-.5))|(!(f>=$(.5))|!(f<=$(1.5))))){do if(!(f<=$(.5))){if(f>=$(1.5)){e=$($(1.5)-c);c=$($(1.5)-b);break}if(!(e<=$(-.5))){e=$(c+$(.5));c=$(b+$(-.5));break}else{e=$(c+$(-.5));c=$(b+$(.5));break}}else{e=$($(.5)-c);c=$($(.5)-b)}while(0);b=e;i=$(e-c);f=$(c+e);g=-1.0}else{i=e;g=1.0}h=$(+b*2.0+-1.0);b=$(+c*2.0+-1.0);l=+f*2.0;j=l+-1.0;l=3.0-l;m=+i*2.0;k=m+1.0;m=1.0-m;k=m
>2]|0;m=(f[f[m>>2]>>2]|0)+(f[m+48>>2]|0)|0;if(!c){c=1;Lo(t);u=v;return c|0}q=p+4|0;l=a+28|0;if(d<<24>>24>0){h=0;i=0;j=0}else{a=0;d=0;while(1){ef((f[f[(f[r>>2]|0)+64>>2]>>2]|0)+d|0,t|0,s|0)|0;a=a+1|0;if((a|0)==(c|0)){a=1;break}else d=d+s|0}Lo(t);u=v;return a|0}while(1){a=f[l>>2]|0;e=$(n[q>>2]);g=$(n[p>>2]);d=0;k=j;while(1){z=f[m+(k<<2)>>2]|0;y=(z|0)<0;w=$(e*$((y?0-z|0:z)|0));x=$(-w);w=$(g*(y?x:w));w=$($(n[a+(d<<2)>>2])+w);n[t+(d<<2)>>2]=w;d=d+1|0;if((d|0)==(o|0))break;else k=k+1|0}ef((f[f[(f[r>>2]|0)+64>>2]>>2]|0)+i|0,t|0,s|0)|0;h=h+1|0;if((h|0)==(c|0)){a=1;break}else{i=i+s|0;j=o+j|0}}Lo(t);u=v;return a|0}function we(a){a=a|0;var b=0,c=0,d=0,e=0,g=0,h=0;g=a+124|0;b=f[g>>2]|0;if(b|0){h=a+128|0;c=f[h>>2]|0;if((c|0)!=(b|0)){do{d=c+-12|0;f[h>>2]=d;e=f[d>>2]|0;if(!e)c=d;else{d=c+-8|0;c=f[d>>2]|0;if((c|0)!=(e|0))f[d>>2]=c+(~((c+-4-e|0)>>>2)<<2);No(e);c=f[h>>2]|0}}while((c|0)!=(b|0));b=f[g>>2]|0}No(b)}g=a+112|0;b=f[g>>2]|0;if(b|0){h=a+116|0;c=f[h>>2]|0;if((c|0)!=(b|0)){do{d=c+-12|0;f[h>>2]=d;e=f[d>>2]|0;if(!e)c=d;else{d=c+-8|0;c=f[d>>2]|0;if((c|0)!=(e|0))f[d>>2]=c+(~((c+-4-e|0)>>>2)<<2);No(e);c=f[h>>2]|0}}while((c|0)!=(b|0));b=f[g>>2]|0}No(b)}b=f[a+100>>2]|0;if(b|0){d=a+104|0;c=f[d>>2]|0;if((c|0)!=(b|0))f[d>>2]=c+(~((c+-4-b|0)>>>2)<<2);No(b)}b=f[a+88>>2]|0;if(!b){h=a+68|0;aj(h);h=a+48|0;aj(h);h=a+28|0;aj(h);a=a+12|0;So(a);return}d=a+92|0;c=f[d>>2]|0;if((c|0)!=(b|0))f[d>>2]=c+(~((c+-4-b|0)>>>2)<<2);No(b);h=a+68|0;aj(h);h=a+48|0;aj(h);h=a+28|0;aj(h);a=a+12|0;So(a);return}function xe(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,g=0,h=0,i=0,j=0,k=0;k=u;u=u+112|0;h=k+96|0;j=k+16|0;i=k+4|0;g=k;c=j+76|0;d=j;e=d+76|0;do{f[d>>2]=0;d=d+4|0}while((d|0)<(e|0));f[c>>2]=-1073741824;f[i>>2]=0;e=i+4|0;f[e>>2]=0;f[i+8>>2]=0;f[g>>2]=i;f[h>>2]=f[g>>2];if(wc(j,a,h)|0){g=f[i>>2]|0;ue(b,g,g+((f[e>>2]|0)-g>>2<<2)|0);g=f[j+68>>2]|0}else g=0;c=f[i>>2]|0;if(c|0){d=f[e>>2]|0;if((d|0)!=(c|0))f[e>>2]=d+(~((d+-4-c|0)>>>2)<<2);No(c)}c=f[j+56>>2]|0;if(c|0)No(c);c=f[j+32>>2]|0;if(c|0){e=j+36|0;d=f[e>>2]|0;if((d|0)!=(c|0))f[e>>2]=d+(~((d+-4-c|0)>>>2)<<2);No(c)}c=f[j+20>>2]|0;if(c|0){e=j+24|0;d=f[e>>2]|0;if((d|0)!=(c|0))f[e>>2]=d+(~((d+-4-c|0)>>>2)<<2);No(c)}c=f[j+8>>2]|0;if(c|0){e=j+12|0;d=f[e>>2]|0;if((d|0)!=(c|0))f[e>>2]=d+(~((d+-4-c|0)>>>2)<<2);No(c)}j=j+4|0;c=f[j>>2]|0;f[j>>2]=0;if(!c){u=k;return g|0}xg(c);No(c);u=k;return g|0}function ye(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;f[a+4>>2]=f[b+4>>2];j=a+8|0;k=b+8|0;if((a|0)==(b|0))return a|0;i=b+12|0;c=f[i>>2]|0;if(!c)c=0;else{h=a+16|0;do if(c>>>0>f[h>>2]<<5>>>0){d=f[j>>2]|0;if(d){No(d);f[j>>2]=0;f[h>>2]=0;f[a+12>>2]=0;c=f[i>>2]|0}if((c|0)<0)co(j);else{e=((c+-1|0)>>>5)+1|0;g=Rk(e<<2)|0;f[j>>2]=g;f[a+12>>2]=0;f[h>>2]=e;e=f[i>>2]|0;break}}else{e=c;g=f[j>>2]|0}while(0);_j(g|0,f[k>>2]|0,((e+-1|0)>>>5<<2)+4|0)|0;c=f[i>>2]|0}f[a+12>>2]=c;h=a+20|0;i=b+20|0;g=b+24|0;c=f[g>>2]|0;if(!c)c=0;else{e=a+28|0;do if(c>>>0>f[e>>2]<<5>>>0){d=f[h>>2]|0;if(d){No(d);f[h>>2]=0;f[e>>2]=0;f[a+24>>2]=0;c=f[g>>2]|0}if((c|0)<0)co(h);else{l=((c+-1|0)>>>5)+1|0;m=Rk(l<<2)|0;f[h>>2]=m;f[a+24>>2]=0;f[e>>2]=l;l=f[g>>2]|0;break}}else{l=c;m=f[h>>2]|0}while(0);_j(m|0,f[i>>2]|0,((l+-1|0)>>>5<<2)+4|0)|0;c=f[g>>2]|0}f[a+24>>2]=c;return a|0}function ze(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,g=0,h=0,i=0,j=0;i=a+8|0;d=f[i>>2]|0;h=f[a>>2]|0;j=h;do if(d-h>>2>>>0>=b>>>0){a=a+4|0;i=f[a>>2]|0;h=i-h>>2;g=h>>>0>>0;d=g?h:b;if(d|0){e=j;while(1){f[e>>2]=f[c>>2];d=d+-1|0;if(!d)break;else e=e+4|0}}if(!g){d=j+(b<<2)|0;if((i|0)==(d|0))return;else{e=a;d=i+(~((i+-4-d|0)>>>2)<<2)|0;break}}else{g=b-h|0;d=i;e=g;while(1){f[d>>2]=f[c>>2];e=e+-1|0;if(!e)break;else d=d+4|0}e=a;d=i+(g<<2)|0;break}}else{g=h;if(h){e=a+4|0;d=f[e>>2]|0;if((d|0)!=(j|0))f[e>>2]=d+(~((d+-4-h|0)>>>2)<<2);No(g);f[i>>2]=0;f[e>>2]=0;f[a>>2]=0;d=0}if(b>>>0>1073741823)co(a);j=d>>1;d=d>>2>>>0<536870911?(j>>>0>>0?b:j):1073741823;if(d>>>0>1073741823)co(a);h=Rk(d<<2)|0;g=a+4|0;f[g>>2]=h;f[a>>2]=h;f[i>>2]=h+(d<<2);d=h;e=b;while(1){f[d>>2]=f[c>>2];e=e+-1|0;if(!e)break;else d=d+4|0}e=g;d=h+(b<<2)|0}while(0);f[e>>2]=d;return}function Ae(a,c){a=a|0;c=c|0;var d=0,e=0,g=0,i=0,j=0,k=0,l=0;f[c>>2]=1;e=a+4|0;l=c+8|0;k=c+12|0;c=f[l>>2]|0;d=(f[k>>2]|0)-c|0;if(d>>>0<4294967292){Fi(l,d+4|0,0);c=f[l>>2]|0}j=c+d|0;i=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[j>>0]=i;b[j+1>>0]=i>>8;b[j+2>>0]=i>>16;b[j+3>>0]=i>>24;j=a+8|0;i=a+12|0;c=f[j>>2]|0;if((f[i>>2]|0)!=(c|0)){g=0;do{d=c+(g<<2)|0;c=f[l>>2]|0;e=(f[k>>2]|0)-c|0;if(e>>>0<4294967292){Fi(l,e+4|0,0);c=f[l>>2]|0}c=c+e|0;e=h[d>>0]|h[d+1>>0]<<8|h[d+2>>0]<<16|h[d+3>>0]<<24;b[c>>0]=e;b[c+1>>0]=e>>8;b[c+2>>0]=e>>16;b[c+3>>0]=e>>24;g=g+1|0;c=f[j>>2]|0}while(g>>>0<(f[i>>2]|0)-c>>2>>>0)}e=a+20|0;d=f[l>>2]|0;c=(f[k>>2]|0)-d|0;if(c>>>0<4294967292){Fi(l,c+4|0,0);l=f[l>>2]|0;l=l+c|0;k=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[l>>0]=k;b[l+1>>0]=k>>8;b[l+2>>0]=k>>16;b[l+3>>0]=k>>24;return}else{l=d;l=l+c|0;k=h[e>>0]|h[e+1>>0]<<8|h[e+2>>0]<<16|h[e+3>>0]<<24;b[l>>0]=k;b[l+1>>0]=k>>8;b[l+2>>0]=k>>16;b[l+3>>0]=k>>24;return}}function Be(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,g=0,h=0,i=0,j=0,k=0,l=0;k=c;e=b;j=k-e|0;h=j>>2;i=a+8|0;d=f[i>>2]|0;g=f[a>>2]|0;l=g;if(h>>>0>d-g>>2>>>0){e=g;if(g){c=a+4|0;d=f[c>>2]|0;if((d|0)!=(l|0))f[c>>2]=d+(~((d+-4-g|0)>>>2)<<2);No(e);f[i>>2]=0;f[c>>2]=0;f[a>>2]=0;d=0}if(h>>>0>1073741823)co(a);l=d>>1;d=d>>2>>>0<536870911?(l>>>0