VoxelInspectorViewModel.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. import {
  2. Cartesian3,
  3. Check,
  4. defined,
  5. destroyObject,
  6. HeadingPitchRoll,
  7. Matrix3,
  8. Matrix4,
  9. CustomShader,
  10. VoxelShapeType,
  11. } from "@cesium/engine";
  12. import knockout from "../ThirdParty/knockout.js";
  13. function formatShaderString(str) {
  14. // This function:
  15. // A) removes whitespace lines at the beginning of the string
  16. // B) removes unnecessary spaces from the beginning of each line
  17. const lines = str.split("\n");
  18. let firstLineIdx;
  19. for (firstLineIdx = 0; firstLineIdx < lines.length; firstLineIdx++) {
  20. if (lines[firstLineIdx].match(/\S/)) {
  21. // Found the first line that's not entirely whitespace
  22. break;
  23. }
  24. }
  25. if (firstLineIdx === lines.length) {
  26. // All lines are empty
  27. return "";
  28. }
  29. let finalStr = "";
  30. const pattern = /^\s*/;
  31. const firstLine = lines[firstLineIdx];
  32. const spacesInFrontOfFirstLine = firstLine.match(pattern)[0].length;
  33. for (let i = firstLineIdx; i < lines.length; i++) {
  34. let line = lines[i];
  35. const spacesInFront = line.match(pattern)[0].length;
  36. if (spacesInFront >= spacesInFrontOfFirstLine) {
  37. line = line.slice(spacesInFrontOfFirstLine);
  38. }
  39. finalStr += `${line}\n`;
  40. }
  41. return finalStr;
  42. }
  43. /**
  44. * The view model for {@link VoxelInspector}.
  45. * @alias VoxelInspectorViewModel
  46. * @constructor
  47. *
  48. * @param {Scene} scene The scene instance to use.
  49. */
  50. function VoxelInspectorViewModel(scene) {
  51. //>>includeStart('debug', pragmas.debug);
  52. Check.typeOf.object("scene", scene);
  53. //>>includeEnd('debug');
  54. this._scene = scene;
  55. this._voxelPrimitive = undefined;
  56. this._customShaderCompilationRemoveCallback = undefined;
  57. this._definedProperties = [];
  58. this._getPrimitiveFunctions = [];
  59. this._modelMatrixReady = false;
  60. const that = this;
  61. function addProperty(options) {
  62. const { name, initialValue } = options;
  63. that._definedProperties.push(name);
  64. let setPrimitiveFunction = options.setPrimitiveFunction;
  65. if (setPrimitiveFunction === true) {
  66. setPrimitiveFunction = function (value) {
  67. that._voxelPrimitive[name] = value;
  68. };
  69. }
  70. let getPrimitiveFunction = options.getPrimitiveFunction;
  71. if (getPrimitiveFunction === true) {
  72. getPrimitiveFunction = function () {
  73. that[name] = that._voxelPrimitive[name];
  74. };
  75. }
  76. if (defined(getPrimitiveFunction)) {
  77. that._getPrimitiveFunctions.push(getPrimitiveFunction);
  78. }
  79. const knock = knockout.observable();
  80. knockout.defineProperty(that, name, {
  81. get: function () {
  82. return knock();
  83. },
  84. set: function (value) {
  85. // Convert input values to the correct type
  86. if (typeof initialValue === "number" && typeof value === "string") {
  87. value = Number(value);
  88. if (isNaN(value)) {
  89. value = initialValue;
  90. }
  91. }
  92. if (typeof initialValue === "boolean" && typeof value === "number") {
  93. value = value === 1 ? true : false;
  94. }
  95. knock(value);
  96. if (defined(setPrimitiveFunction) && defined(that._voxelPrimitive)) {
  97. setPrimitiveFunction(value);
  98. scene.requestRender();
  99. }
  100. },
  101. });
  102. that[name] = initialValue;
  103. return knock;
  104. }
  105. function getBoundSetter(boundKey, component) {
  106. return function (value) {
  107. const bound = that._voxelPrimitive[boundKey].clone();
  108. bound[component] = value;
  109. that._voxelPrimitive[boundKey] = bound;
  110. };
  111. }
  112. addProperty({
  113. name: "inspectorVisible",
  114. initialValue: true,
  115. });
  116. addProperty({
  117. name: "displayVisible",
  118. initialValue: false,
  119. });
  120. addProperty({
  121. name: "transformVisible",
  122. initialValue: false,
  123. });
  124. addProperty({
  125. name: "boundsVisible",
  126. initialValue: false,
  127. });
  128. addProperty({
  129. name: "clippingVisible",
  130. initialValue: false,
  131. });
  132. addProperty({
  133. name: "shaderVisible",
  134. initialValue: false,
  135. });
  136. addProperty({
  137. name: "shaderString",
  138. initialValue: "",
  139. getPrimitiveFunction: function () {
  140. const shaderString = that._voxelPrimitive.customShader.fragmentShaderText;
  141. that.shaderString = formatShaderString(shaderString);
  142. },
  143. });
  144. addProperty({
  145. name: "shaderCompilationMessage",
  146. initialValue: "",
  147. });
  148. addProperty({
  149. name: "shaderCompilationSuccess",
  150. initialValue: true,
  151. });
  152. addProperty({
  153. name: "depthTest",
  154. initialValue: false,
  155. setPrimitiveFunction: true,
  156. getPrimitiveFunction: true,
  157. });
  158. addProperty({
  159. name: "show",
  160. initialValue: true,
  161. setPrimitiveFunction: true,
  162. getPrimitiveFunction: true,
  163. });
  164. addProperty({
  165. name: "disableUpdate",
  166. initialValue: false,
  167. setPrimitiveFunction: true,
  168. getPrimitiveFunction: true,
  169. });
  170. addProperty({
  171. name: "debugDraw",
  172. initialValue: false,
  173. setPrimitiveFunction: true,
  174. getPrimitiveFunction: true,
  175. });
  176. addProperty({
  177. name: "jitter",
  178. initialValue: true,
  179. setPrimitiveFunction: true,
  180. getPrimitiveFunction: true,
  181. });
  182. addProperty({
  183. name: "nearestSampling",
  184. initialValue: true,
  185. setPrimitiveFunction: true,
  186. getPrimitiveFunction: true,
  187. });
  188. addProperty({
  189. name: "screenSpaceError",
  190. initialValue: 4.0,
  191. setPrimitiveFunction: true,
  192. getPrimitiveFunction: true,
  193. });
  194. addProperty({
  195. name: "stepSize",
  196. initialValue: 1.0,
  197. setPrimitiveFunction: true,
  198. getPrimitiveFunction: true,
  199. });
  200. addProperty({
  201. name: "shapeIsBox",
  202. getPrimitiveFunction: function () {
  203. const shapeType = that._voxelPrimitive.shape;
  204. that.shapeIsBox = shapeType === VoxelShapeType.BOX;
  205. },
  206. });
  207. addProperty({
  208. name: "shapeIsEllipsoid",
  209. getPrimitiveFunction: function () {
  210. const shapeType = that._voxelPrimitive.shape;
  211. that.shapeIsEllipsoid = shapeType === VoxelShapeType.ELLIPSOID;
  212. },
  213. });
  214. addProperty({
  215. name: "shapeIsCylinder",
  216. getPrimitiveFunction: function () {
  217. const shapeType = that._voxelPrimitive.shape;
  218. that.shapeIsCylinder = shapeType === VoxelShapeType.CYLINDER;
  219. },
  220. });
  221. addProperty({
  222. name: "boundsBoxMaxX",
  223. initialValue: 0.0,
  224. setPrimitiveFunction: getBoundSetter("maxBounds", "x"),
  225. getPrimitiveFunction: function () {
  226. that.boundsBoxMaxX = that._voxelPrimitive.maxBounds.x;
  227. },
  228. });
  229. addProperty({
  230. name: "boundsBoxMinX",
  231. initialValue: 0.0,
  232. setPrimitiveFunction: getBoundSetter("minBounds", "x"),
  233. getPrimitiveFunction: function () {
  234. that.boundsBoxMinX = that._voxelPrimitive.minBounds.x;
  235. },
  236. });
  237. addProperty({
  238. name: "boundsBoxMaxY",
  239. initialValue: 0.0,
  240. setPrimitiveFunction: getBoundSetter("maxBounds", "y"),
  241. getPrimitiveFunction: function () {
  242. that.boundsBoxMaxY = that._voxelPrimitive.maxBounds.y;
  243. },
  244. });
  245. addProperty({
  246. name: "boundsBoxMinY",
  247. initialValue: 0.0,
  248. setPrimitiveFunction: getBoundSetter("minBounds", "y"),
  249. getPrimitiveFunction: function () {
  250. that.boundsBoxMinY = that._voxelPrimitive.minBounds.y;
  251. },
  252. });
  253. addProperty({
  254. name: "boundsBoxMaxZ",
  255. initialValue: 0.0,
  256. setPrimitiveFunction: getBoundSetter("maxBounds", "z"),
  257. getPrimitiveFunction: function () {
  258. that.boundsBoxMaxZ = that._voxelPrimitive.maxBounds.z;
  259. },
  260. });
  261. addProperty({
  262. name: "boundsBoxMinZ",
  263. initialValue: 0.0,
  264. setPrimitiveFunction: getBoundSetter("minBounds", "z"),
  265. getPrimitiveFunction: function () {
  266. that.boundsBoxMinZ = that._voxelPrimitive.minBounds.z;
  267. },
  268. });
  269. addProperty({
  270. name: "boundsEllipsoidMaxLongitude",
  271. initialValue: 0.0,
  272. setPrimitiveFunction: getBoundSetter("maxBounds", "x"),
  273. getPrimitiveFunction: function () {
  274. that.boundsEllipsoidMaxLongitude = that._voxelPrimitive.maxBounds.x;
  275. },
  276. });
  277. addProperty({
  278. name: "boundsEllipsoidMinLongitude",
  279. initialValue: 0.0,
  280. setPrimitiveFunction: getBoundSetter("minBounds", "x"),
  281. getPrimitiveFunction: function () {
  282. that.boundsEllipsoidMinLongitude = that._voxelPrimitive.minBounds.x;
  283. },
  284. });
  285. addProperty({
  286. name: "boundsEllipsoidMaxLatitude",
  287. initialValue: 0.0,
  288. setPrimitiveFunction: getBoundSetter("maxBounds", "y"),
  289. getPrimitiveFunction: function () {
  290. that.boundsEllipsoidMaxLatitude = that._voxelPrimitive.maxBounds.y;
  291. },
  292. });
  293. addProperty({
  294. name: "boundsEllipsoidMinLatitude",
  295. initialValue: 0.0,
  296. setPrimitiveFunction: getBoundSetter("minBounds", "y"),
  297. getPrimitiveFunction: function () {
  298. that.boundsEllipsoidMinLatitude = that._voxelPrimitive.minBounds.y;
  299. },
  300. });
  301. addProperty({
  302. name: "boundsEllipsoidMaxHeight",
  303. initialValue: 0.0,
  304. setPrimitiveFunction: getBoundSetter("maxBounds", "z"),
  305. getPrimitiveFunction: function () {
  306. that.boundsEllipsoidMaxHeight = that._voxelPrimitive.maxBounds.z;
  307. },
  308. });
  309. addProperty({
  310. name: "boundsEllipsoidMinHeight",
  311. initialValue: 0.0,
  312. setPrimitiveFunction: getBoundSetter("minBounds", "z"),
  313. getPrimitiveFunction: function () {
  314. that.boundsEllipsoidMinHeight = that._voxelPrimitive.minBounds.z;
  315. },
  316. });
  317. addProperty({
  318. name: "boundsCylinderMaxRadius",
  319. initialValue: 0.0,
  320. setPrimitiveFunction: getBoundSetter("maxBounds", "x"),
  321. getPrimitiveFunction: function () {
  322. that.boundsCylinderMaxRadius = that._voxelPrimitive.maxBounds.x;
  323. },
  324. });
  325. addProperty({
  326. name: "boundsCylinderMinRadius",
  327. initialValue: 0.0,
  328. setPrimitiveFunction: getBoundSetter("minBounds", "x"),
  329. getPrimitiveFunction: function () {
  330. that.boundsCylinderMinRadius = that._voxelPrimitive.minBounds.x;
  331. },
  332. });
  333. addProperty({
  334. name: "boundsCylinderMaxHeight",
  335. initialValue: 0.0,
  336. setPrimitiveFunction: getBoundSetter("maxBounds", "y"),
  337. getPrimitiveFunction: function () {
  338. that.boundsCylinderMaxHeight = that._voxelPrimitive.maxBounds.y;
  339. },
  340. });
  341. addProperty({
  342. name: "boundsCylinderMinHeight",
  343. initialValue: 0.0,
  344. setPrimitiveFunction: getBoundSetter("minBounds", "y"),
  345. getPrimitiveFunction: function () {
  346. that.boundsCylinderMinHeight = that._voxelPrimitive.minBounds.y;
  347. },
  348. });
  349. addProperty({
  350. name: "boundsCylinderMaxAngle",
  351. initialValue: 0.0,
  352. setPrimitiveFunction: getBoundSetter("maxBounds", "z"),
  353. getPrimitiveFunction: function () {
  354. that.boundsCylinderMaxAngle = that._voxelPrimitive.maxBounds.z;
  355. },
  356. });
  357. addProperty({
  358. name: "boundsCylinderMinAngle",
  359. initialValue: 0.0,
  360. setPrimitiveFunction: getBoundSetter("minBounds", "z"),
  361. getPrimitiveFunction: function () {
  362. that.boundsCylinderMinAngle = that._voxelPrimitive.minBounds.z;
  363. },
  364. });
  365. addProperty({
  366. name: "clippingBoxMaxX",
  367. initialValue: 0.0,
  368. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "x"),
  369. getPrimitiveFunction: function () {
  370. that.clippingBoxMaxX = that._voxelPrimitive.maxClippingBounds.x;
  371. },
  372. });
  373. addProperty({
  374. name: "clippingBoxMinX",
  375. initialValue: 0.0,
  376. setPrimitiveFunction: getBoundSetter("minClippingBounds", "x"),
  377. getPrimitiveFunction: function () {
  378. that.clippingBoxMinX = that._voxelPrimitive.minClippingBounds.x;
  379. },
  380. });
  381. addProperty({
  382. name: "clippingBoxMaxY",
  383. initialValue: 0.0,
  384. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "y"),
  385. getPrimitiveFunction: function () {
  386. that.clippingBoxMaxY = that._voxelPrimitive.maxClippingBounds.y;
  387. },
  388. });
  389. addProperty({
  390. name: "clippingBoxMinY",
  391. initialValue: 0.0,
  392. setPrimitiveFunction: getBoundSetter("minClippingBounds", "y"),
  393. getPrimitiveFunction: function () {
  394. that.clippingBoxMinY = that._voxelPrimitive.minClippingBounds.y;
  395. },
  396. });
  397. addProperty({
  398. name: "clippingBoxMaxZ",
  399. initialValue: 0.0,
  400. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "z"),
  401. getPrimitiveFunction: function () {
  402. that.clippingBoxMaxZ = that._voxelPrimitive.maxClippingBounds.z;
  403. },
  404. });
  405. addProperty({
  406. name: "clippingBoxMinZ",
  407. initialValue: 0.0,
  408. setPrimitiveFunction: getBoundSetter("minClippingBounds", "z"),
  409. getPrimitiveFunction: function () {
  410. that.clippingBoxMinZ = that._voxelPrimitive.minClippingBounds.z;
  411. },
  412. });
  413. addProperty({
  414. name: "clippingEllipsoidMaxLongitude",
  415. initialValue: 0.0,
  416. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "x"),
  417. getPrimitiveFunction: function () {
  418. that.clippingEllipsoidMaxLongitude =
  419. that._voxelPrimitive.maxClippingBounds.x;
  420. },
  421. });
  422. addProperty({
  423. name: "clippingEllipsoidMinLongitude",
  424. initialValue: 0.0,
  425. setPrimitiveFunction: getBoundSetter("minClippingBounds", "x"),
  426. getPrimitiveFunction: function () {
  427. that.clippingEllipsoidMinLongitude =
  428. that._voxelPrimitive.minClippingBounds.x;
  429. },
  430. });
  431. addProperty({
  432. name: "clippingEllipsoidMaxLatitude",
  433. initialValue: 0.0,
  434. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "y"),
  435. getPrimitiveFunction: function () {
  436. that.clippingEllipsoidMaxLatitude =
  437. that._voxelPrimitive.maxClippingBounds.y;
  438. },
  439. });
  440. addProperty({
  441. name: "clippingEllipsoidMinLatitude",
  442. initialValue: 0.0,
  443. setPrimitiveFunction: getBoundSetter("minClippingBounds", "y"),
  444. getPrimitiveFunction: function () {
  445. that.clippingEllipsoidMinLatitude =
  446. that._voxelPrimitive.minClippingBounds.y;
  447. },
  448. });
  449. addProperty({
  450. name: "clippingEllipsoidMaxHeight",
  451. initialValue: 0.0,
  452. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "z"),
  453. getPrimitiveFunction: function () {
  454. that.clippingEllipsoidMaxHeight =
  455. that._voxelPrimitive.maxClippingBounds.z;
  456. },
  457. });
  458. addProperty({
  459. name: "clippingEllipsoidMinHeight",
  460. initialValue: 0.0,
  461. setPrimitiveFunction: getBoundSetter("minClippingBounds", "z"),
  462. getPrimitiveFunction: function () {
  463. that.clippingEllipsoidMinHeight =
  464. that._voxelPrimitive.minClippingBounds.z;
  465. },
  466. });
  467. addProperty({
  468. name: "clippingCylinderMaxRadius",
  469. initialValue: 0.0,
  470. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "x"),
  471. getPrimitiveFunction: function () {
  472. that.clippingCylinderMaxRadius = that._voxelPrimitive.maxClippingBounds.x;
  473. },
  474. });
  475. addProperty({
  476. name: "clippingCylinderMinRadius",
  477. initialValue: 0.0,
  478. setPrimitiveFunction: getBoundSetter("minClippingBounds", "x"),
  479. getPrimitiveFunction: function () {
  480. that.clippingCylinderMinRadius = that._voxelPrimitive.minClippingBounds.x;
  481. },
  482. });
  483. addProperty({
  484. name: "clippingCylinderMaxHeight",
  485. initialValue: 0.0,
  486. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "y"),
  487. getPrimitiveFunction: function () {
  488. that.clippingCylinderMaxHeight = that._voxelPrimitive.maxClippingBounds.y;
  489. },
  490. });
  491. addProperty({
  492. name: "clippingCylinderMinHeight",
  493. initialValue: 0.0,
  494. setPrimitiveFunction: getBoundSetter("minClippingBounds", "y"),
  495. getPrimitiveFunction: function () {
  496. that.clippingCylinderMinHeight = that._voxelPrimitive.minClippingBounds.y;
  497. },
  498. });
  499. addProperty({
  500. name: "clippingCylinderMaxAngle",
  501. initialValue: 0.0,
  502. setPrimitiveFunction: getBoundSetter("maxClippingBounds", "z"),
  503. getPrimitiveFunction: function () {
  504. that.clippingCylinderMaxAngle = that._voxelPrimitive.maxClippingBounds.z;
  505. },
  506. });
  507. addProperty({
  508. name: "clippingCylinderMinAngle",
  509. initialValue: 0.0,
  510. setPrimitiveFunction: getBoundSetter("minClippingBounds", "z"),
  511. getPrimitiveFunction: function () {
  512. that.clippingCylinderMinAngle = that._voxelPrimitive.minClippingBounds.z;
  513. },
  514. });
  515. addProperty({
  516. name: "translationX",
  517. initialValue: 0.0,
  518. setPrimitiveFunction: function () {
  519. if (that._modelMatrixReady) {
  520. setModelMatrix(that);
  521. }
  522. },
  523. getPrimitiveFunction: function () {
  524. that.translationX = Matrix4.getTranslation(
  525. that._voxelPrimitive.modelMatrix,
  526. new Cartesian3()
  527. ).x;
  528. },
  529. });
  530. addProperty({
  531. name: "translationY",
  532. initialValue: 0.0,
  533. setPrimitiveFunction: function () {
  534. if (that._modelMatrixReady) {
  535. setModelMatrix(that);
  536. }
  537. },
  538. getPrimitiveFunction: function () {
  539. that.translationY = Matrix4.getTranslation(
  540. that._voxelPrimitive.modelMatrix,
  541. new Cartesian3()
  542. ).y;
  543. },
  544. });
  545. addProperty({
  546. name: "translationZ",
  547. initialValue: 0.0,
  548. setPrimitiveFunction: function () {
  549. if (that._modelMatrixReady) {
  550. setModelMatrix(that);
  551. }
  552. },
  553. getPrimitiveFunction: function () {
  554. that.translationZ = Matrix4.getTranslation(
  555. that._voxelPrimitive.modelMatrix,
  556. new Cartesian3()
  557. ).z;
  558. },
  559. });
  560. addProperty({
  561. name: "scaleX",
  562. initialValue: 1.0,
  563. setPrimitiveFunction: function () {
  564. if (that._modelMatrixReady) {
  565. setModelMatrix(that);
  566. }
  567. },
  568. getPrimitiveFunction: function () {
  569. that.scaleX = Matrix4.getScale(
  570. that._voxelPrimitive.modelMatrix,
  571. new Cartesian3()
  572. ).x;
  573. },
  574. });
  575. addProperty({
  576. name: "scaleY",
  577. initialValue: 1.0,
  578. setPrimitiveFunction: function () {
  579. if (that._modelMatrixReady) {
  580. setModelMatrix(that);
  581. }
  582. },
  583. getPrimitiveFunction: function () {
  584. that.scaleY = Matrix4.getScale(
  585. that._voxelPrimitive.modelMatrix,
  586. new Cartesian3()
  587. ).y;
  588. },
  589. });
  590. addProperty({
  591. name: "scaleZ",
  592. initialValue: 1.0,
  593. setPrimitiveFunction: function () {
  594. if (that._modelMatrixReady) {
  595. setModelMatrix(that);
  596. }
  597. },
  598. getPrimitiveFunction: function () {
  599. that.scaleZ = Matrix4.getScale(
  600. that._voxelPrimitive.modelMatrix,
  601. new Cartesian3()
  602. ).z;
  603. },
  604. });
  605. addProperty({
  606. name: "angleX",
  607. initialValue: 0.0,
  608. setPrimitiveFunction: function () {
  609. if (that._modelMatrixReady) {
  610. setModelMatrix(that);
  611. }
  612. },
  613. });
  614. addProperty({
  615. name: "angleY",
  616. initialValue: 0.0,
  617. setPrimitiveFunction: function () {
  618. if (that._modelMatrixReady) {
  619. setModelMatrix(that);
  620. }
  621. },
  622. });
  623. addProperty({
  624. name: "angleZ",
  625. initialValue: 0.0,
  626. setPrimitiveFunction: function () {
  627. if (that._modelMatrixReady) {
  628. setModelMatrix(that);
  629. }
  630. },
  631. });
  632. }
  633. const scratchTranslation = new Cartesian3();
  634. const scratchScale = new Cartesian3();
  635. const scratchHeadingPitchRoll = new HeadingPitchRoll();
  636. const scratchRotation = new Matrix3();
  637. function setModelMatrix(viewModel) {
  638. const translation = Cartesian3.fromElements(
  639. viewModel.translationX,
  640. viewModel.translationY,
  641. viewModel.translationZ,
  642. scratchTranslation
  643. );
  644. const scale = Cartesian3.fromElements(
  645. viewModel.scaleX,
  646. viewModel.scaleY,
  647. viewModel.scaleZ,
  648. scratchScale
  649. );
  650. const hpr = scratchHeadingPitchRoll;
  651. hpr.heading = viewModel.angleX;
  652. hpr.pitch = viewModel.angleY;
  653. hpr.roll = viewModel.angleZ;
  654. const rotation = Matrix3.fromHeadingPitchRoll(hpr, scratchRotation);
  655. const rotationScale = Matrix3.multiplyByScale(rotation, scale, rotation);
  656. viewModel._voxelPrimitive.modelMatrix = Matrix4.fromRotationTranslation(
  657. rotationScale,
  658. translation,
  659. viewModel._voxelPrimitive.modelMatrix
  660. );
  661. }
  662. Object.defineProperties(VoxelInspectorViewModel.prototype, {
  663. /**
  664. * Gets the scene
  665. * @memberof VoxelInspectorViewModel.prototype
  666. * @type {Scene}
  667. * @readonly
  668. */
  669. scene: {
  670. get: function () {
  671. return this._scene;
  672. },
  673. },
  674. /**
  675. * Gets or sets the primitive of the view model.
  676. * @memberof VoxelInspectorViewModel.prototype
  677. * @type {VoxelPrimitive}
  678. */
  679. voxelPrimitive: {
  680. get: function () {
  681. return this._voxelPrimitive;
  682. },
  683. set: function (voxelPrimitive) {
  684. if (defined(this._customShaderCompilationRemoveCallback)) {
  685. this._customShaderCompilationRemoveCallback();
  686. }
  687. // Update properties from the new primitive
  688. if (defined(voxelPrimitive)) {
  689. this._voxelPrimitive = voxelPrimitive;
  690. const that = this;
  691. // This is here for backwards compatibility. This can be done immediately once readyPromise is removed.
  692. that._voxelPrimitive._readyPromise.then(function () {
  693. that._customShaderCompilationRemoveCallback = that._voxelPrimitive.customShaderCompilationEvent.addEventListener(
  694. function (error) {
  695. const shaderString =
  696. that._voxelPrimitive.customShader.fragmentShaderText;
  697. that.shaderString = formatShaderString(shaderString);
  698. if (!defined(error)) {
  699. that.shaderCompilationMessage = "Shader compiled successfully!";
  700. that.shaderCompilationSuccess = true;
  701. } else {
  702. that.shaderCompilationMessage = error.message;
  703. that.shaderCompilationSuccess = false;
  704. }
  705. }
  706. );
  707. that._modelMatrixReady = false;
  708. for (let i = 0; i < that._getPrimitiveFunctions.length; i++) {
  709. that._getPrimitiveFunctions[i]();
  710. }
  711. that._modelMatrixReady = true;
  712. setModelMatrix(that);
  713. });
  714. }
  715. },
  716. },
  717. });
  718. /**
  719. * Toggles the inspector visibility
  720. */
  721. VoxelInspectorViewModel.prototype.toggleInspector = function () {
  722. this.inspectorVisible = !this.inspectorVisible;
  723. };
  724. /**
  725. * Toggles the visibility of the display section
  726. */
  727. VoxelInspectorViewModel.prototype.toggleDisplay = function () {
  728. this.displayVisible = !this.displayVisible;
  729. };
  730. /**
  731. * Toggles the visibility of the transform section
  732. */
  733. VoxelInspectorViewModel.prototype.toggleTransform = function () {
  734. this.transformVisible = !this.transformVisible;
  735. };
  736. /**
  737. * Toggles the visibility of the bounds section
  738. */
  739. VoxelInspectorViewModel.prototype.toggleBounds = function () {
  740. this.boundsVisible = !this.boundsVisible;
  741. };
  742. /**
  743. * Toggles the visibility of the clipping section
  744. */
  745. VoxelInspectorViewModel.prototype.toggleClipping = function () {
  746. this.clippingVisible = !this.clippingVisible;
  747. };
  748. /**
  749. * Toggles the visibility of the shader section
  750. */
  751. VoxelInspectorViewModel.prototype.toggleShader = function () {
  752. this.shaderVisible = !this.shaderVisible;
  753. };
  754. /**
  755. * Compiles the shader in the shader editor.
  756. */
  757. VoxelInspectorViewModel.prototype.compileShader = function () {
  758. if (defined(this._voxelPrimitive)) {
  759. // It's assumed that the same uniforms are going to be used regardless of edits.
  760. this._voxelPrimitive.customShader = new CustomShader({
  761. fragmentShaderText: this.shaderString,
  762. uniforms: this._voxelPrimitive.customShader.uniforms,
  763. });
  764. }
  765. };
  766. /**
  767. * Handles key press events on the shader editor.
  768. */
  769. VoxelInspectorViewModel.prototype.shaderEditorKeyPress = function (
  770. sender,
  771. event
  772. ) {
  773. if (event.keyCode === 9) {
  774. //tab
  775. event.preventDefault();
  776. const textArea = event.target;
  777. const start = textArea.selectionStart;
  778. const end = textArea.selectionEnd;
  779. let newEnd = end;
  780. const selected = textArea.value.slice(start, end);
  781. const lines = selected.split("\n");
  782. const length = lines.length;
  783. let i;
  784. if (!event.shiftKey) {
  785. for (i = 0; i < length; ++i) {
  786. lines[i] = ` ${lines[i]}`;
  787. newEnd += 2;
  788. }
  789. } else {
  790. for (i = 0; i < length; ++i) {
  791. if (lines[i][0] === " ") {
  792. if (lines[i][1] === " ") {
  793. lines[i] = lines[i].substr(2);
  794. newEnd -= 2;
  795. } else {
  796. lines[i] = lines[i].substr(1);
  797. newEnd -= 1;
  798. }
  799. }
  800. }
  801. }
  802. const newText = lines.join("\n");
  803. textArea.value =
  804. textArea.value.slice(0, start) + newText + textArea.value.slice(end);
  805. textArea.selectionStart = start !== end ? start : newEnd;
  806. textArea.selectionEnd = newEnd;
  807. } else if (event.ctrlKey && (event.keyCode === 10 || event.keyCode === 13)) {
  808. //ctrl + enter
  809. this.compileShader();
  810. }
  811. return true;
  812. };
  813. /**
  814. * @returns {boolean} true if the object has been destroyed, false otherwise.
  815. */
  816. VoxelInspectorViewModel.prototype.isDestroyed = function () {
  817. return false;
  818. };
  819. /**
  820. * Destroys the widget. Should be called if permanently
  821. * removing the widget from layout.
  822. */
  823. VoxelInspectorViewModel.prototype.destroy = function () {
  824. const that = this;
  825. this._definedProperties.forEach(function (property) {
  826. knockout.getObservable(that, property).dispose();
  827. });
  828. return destroyObject(this);
  829. };
  830. export default VoxelInspectorViewModel;