智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. // @ts-check
  2. import Frozen from "../Core/Frozen.js";
  3. import defined from "../Core/defined.js";
  4. import PrimitiveType from "../Core/PrimitiveType.js";
  5. /** @import Context from "./Context.js"; */
  6. /** @import Framebuffer from "./Framebuffer.js"; */
  7. /** @import Matrix4 from "../Core/Matrix4.js"; */
  8. /** @import OrientedBoundingBox from "../Core/OrientedBoundingBox.js"; */
  9. /** @import Pass from "./Pass.js"; */
  10. /** @import PassState from "./PassState.js"; */
  11. /** @import PickedMetadataInfo from "../Scene/PickedMetadataInfo.js"; */
  12. /** @import RenderState from "./RenderState.js"; */
  13. /** @import ShaderProgram from "./ShaderProgram.js"; */
  14. /** @import VertexArray from "./VertexArray.js"; */
  15. /**
  16. * @enum {number}
  17. * @ignore
  18. */
  19. const Flags = {
  20. CULL: 1,
  21. OCCLUDE: 2,
  22. EXECUTE_IN_CLOSEST_FRUSTUM: 4,
  23. DEBUG_SHOW_BOUNDING_VOLUME: 8,
  24. CAST_SHADOWS: 16,
  25. RECEIVE_SHADOWS: 32,
  26. PICK_ONLY: 64,
  27. DEPTH_FOR_TRANSLUCENT_CLASSIFICATION: 128,
  28. };
  29. /**
  30. * @typedef {object} DrawCommandOptions
  31. * @property {object} [boundingVolume]
  32. * @property {OrientedBoundingBox} [orientedBoundingBox]
  33. * @property {Matrix4} [modelMatrix]
  34. * @property {PrimitiveType} [primitiveType=PrimitiveType.TRIANGLES]
  35. * @property {VertexArray} [vertexArray]
  36. * @property {number} [count]
  37. * @property {number} [offset]
  38. * @property {number} [instanceCount]
  39. * @property {ShaderProgram} [shaderProgram]
  40. * @property {object} [uniformMap]
  41. * @property {RenderState} [renderState]
  42. * @property {Framebuffer} [framebuffer]
  43. * @property {Pass} [pass]
  44. * @property {object} [owner]
  45. * @property {string} [pickId]
  46. * @property {boolean} [pickMetadataAllowed=false]
  47. * @property {boolean} [cull=true]
  48. * @property {boolean} [occlude=true]
  49. * @property {boolean} [executeInClosestFrustum=false]
  50. * @property {boolean} [debugShowBoundingVolume=false]
  51. * @property {boolean} [castShadows=false]
  52. * @property {boolean} [receiveShadows=false]
  53. * @property {boolean} [pickOnly=false]
  54. * @property {boolean} [depthForTranslucentClassification=false]
  55. *
  56. * @ignore
  57. */
  58. /**
  59. * Represents a command to the renderer for drawing.
  60. *
  61. * @private
  62. */
  63. class DrawCommand {
  64. /**
  65. * @param {DrawCommandOptions} [options]
  66. */
  67. constructor(options = Frozen.EMPTY_OBJECT) {
  68. /** @private */
  69. this._boundingVolume = options.boundingVolume;
  70. /** @private */
  71. this._orientedBoundingBox = options.orientedBoundingBox;
  72. /** @private */
  73. this._modelMatrix = options.modelMatrix;
  74. /** @private */
  75. this._primitiveType = options.primitiveType ?? PrimitiveType.TRIANGLES;
  76. /** @private */
  77. this._vertexArray = options.vertexArray;
  78. /** @private */
  79. this._count = options.count;
  80. /** @private */
  81. this._offset = options.offset ?? 0;
  82. /** @private */
  83. this._instanceCount = options.instanceCount ?? 0;
  84. /** @private */
  85. this._shaderProgram = options.shaderProgram;
  86. /** @private */
  87. this._uniformMap = options.uniformMap;
  88. /** @private */
  89. this._renderState = options.renderState;
  90. /** @private */
  91. this._framebuffer = options.framebuffer;
  92. /** @private */
  93. this._pass = options.pass;
  94. /** @private */
  95. this._owner = options.owner;
  96. /** @private */
  97. this._debugOverlappingFrustums = 0;
  98. /** @private */
  99. this._pickId = options.pickId;
  100. /** @private */
  101. this._pickMetadataAllowed = options.pickMetadataAllowed === true;
  102. /**
  103. * @type {PickedMetadataInfo|undefined}
  104. * @private
  105. */
  106. this._pickedMetadataInfo = undefined;
  107. // Set initial flags.
  108. this._flags = 0;
  109. this.cull = options.cull ?? true;
  110. this.occlude = options.occlude ?? true;
  111. this.executeInClosestFrustum = options.executeInClosestFrustum ?? false;
  112. this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false;
  113. this.castShadows = options.castShadows ?? false;
  114. this.receiveShadows = options.receiveShadows ?? false;
  115. this.pickOnly = options.pickOnly ?? false;
  116. this.depthForTranslucentClassification =
  117. options.depthForTranslucentClassification ?? false;
  118. this.dirty = true;
  119. this.lastDirtyTime = 0;
  120. /**
  121. * @private
  122. */
  123. this.derivedCommands = {};
  124. }
  125. /**
  126. * The bounding volume of the geometry in world space. This is used for culling and frustum selection.
  127. * <p>
  128. * For best rendering performance, use the tightest possible bounding volume. Although
  129. * <code>undefined</code> is allowed, always try to provide a bounding volume to
  130. * allow the tightest possible near and far planes to be computed for the scene, and
  131. * minimize the number of frustums needed.
  132. * </p>
  133. *
  134. * @type {object}
  135. * @default undefined
  136. *
  137. * @see DrawCommand#debugShowBoundingVolume
  138. */
  139. get boundingVolume() {
  140. return this._boundingVolume;
  141. }
  142. set boundingVolume(value) {
  143. if (this._boundingVolume !== value) {
  144. this._boundingVolume = value;
  145. this.dirty = true;
  146. }
  147. }
  148. /**
  149. * The oriented bounding box of the geometry in world space. If this is defined, it is used instead of
  150. * {@link DrawCommand#boundingVolume} for plane intersection testing.
  151. *
  152. * @type {OrientedBoundingBox}
  153. * @default undefined
  154. *
  155. * @see DrawCommand#debugShowBoundingVolume
  156. */
  157. get orientedBoundingBox() {
  158. return this._orientedBoundingBox;
  159. }
  160. set orientedBoundingBox(value) {
  161. if (this._orientedBoundingBox !== value) {
  162. this._orientedBoundingBox = value;
  163. this.dirty = true;
  164. }
  165. }
  166. /**
  167. * When <code>true</code>, the renderer frustum and horizon culls the command based on its {@link DrawCommand#boundingVolume}.
  168. * If the command was already culled, set this to <code>false</code> for a performance improvement.
  169. *
  170. * @type {boolean}
  171. * @default true
  172. */
  173. get cull() {
  174. return hasFlag(this, Flags.CULL);
  175. }
  176. set cull(value) {
  177. if (hasFlag(this, Flags.CULL) !== value) {
  178. setFlag(this, Flags.CULL, value);
  179. this.dirty = true;
  180. }
  181. }
  182. /**
  183. * When <code>true</code>, the horizon culls the command based on its {@link DrawCommand#boundingVolume}.
  184. * {@link DrawCommand#cull} must also be <code>true</code> in order for the command to be culled.
  185. *
  186. * @type {boolean}
  187. * @default true
  188. */
  189. get occlude() {
  190. return hasFlag(this, Flags.OCCLUDE);
  191. }
  192. set occlude(value) {
  193. if (hasFlag(this, Flags.OCCLUDE) !== value) {
  194. setFlag(this, Flags.OCCLUDE, value);
  195. this.dirty = true;
  196. }
  197. }
  198. /**
  199. * The transformation from the geometry in model space to world space.
  200. * <p>
  201. * When <code>undefined</code>, the geometry is assumed to be defined in world space.
  202. * </p>
  203. *
  204. * @type {Matrix4}
  205. * @default undefined
  206. */
  207. get modelMatrix() {
  208. return this._modelMatrix;
  209. }
  210. set modelMatrix(value) {
  211. if (this._modelMatrix !== value) {
  212. this._modelMatrix = value;
  213. this.dirty = true;
  214. }
  215. }
  216. /**
  217. * The type of geometry in the vertex array.
  218. *
  219. * @type {PrimitiveType}
  220. * @default PrimitiveType.TRIANGLES
  221. */
  222. get primitiveType() {
  223. return this._primitiveType;
  224. }
  225. set primitiveType(value) {
  226. if (this._primitiveType !== value) {
  227. this._primitiveType = value;
  228. this.dirty = true;
  229. }
  230. }
  231. /**
  232. * The vertex array.
  233. *
  234. * @type {VertexArray}
  235. * @default undefined
  236. */
  237. get vertexArray() {
  238. return this._vertexArray;
  239. }
  240. set vertexArray(value) {
  241. if (this._vertexArray !== value) {
  242. this._vertexArray = value;
  243. this.dirty = true;
  244. }
  245. }
  246. /**
  247. * The number of vertices to draw in the vertex array.
  248. *
  249. * @type {number}
  250. * @default undefined
  251. */
  252. get count() {
  253. return this._count;
  254. }
  255. set count(value) {
  256. if (this._count !== value) {
  257. this._count = value;
  258. this.dirty = true;
  259. }
  260. }
  261. /**
  262. * The offset to start drawing in the vertex array.
  263. *
  264. * @type {number}
  265. * @default 0
  266. */
  267. get offset() {
  268. return this._offset;
  269. }
  270. set offset(value) {
  271. if (this._offset !== value) {
  272. this._offset = value;
  273. this.dirty = true;
  274. }
  275. }
  276. /**
  277. * The number of instances to draw.
  278. *
  279. * @type {number}
  280. * @default 0
  281. */
  282. get instanceCount() {
  283. return this._instanceCount;
  284. }
  285. set instanceCount(value) {
  286. if (this._instanceCount !== value) {
  287. this._instanceCount = value;
  288. this.dirty = true;
  289. }
  290. }
  291. /**
  292. * The shader program to apply.
  293. *
  294. * @type {ShaderProgram}
  295. * @default undefined
  296. */
  297. get shaderProgram() {
  298. return this._shaderProgram;
  299. }
  300. set shaderProgram(value) {
  301. if (this._shaderProgram !== value) {
  302. this._shaderProgram = value;
  303. this.dirty = true;
  304. }
  305. }
  306. /**
  307. * Whether this command should cast shadows when shadowing is enabled.
  308. *
  309. * @type {boolean}
  310. * @default false
  311. */
  312. get castShadows() {
  313. return hasFlag(this, Flags.CAST_SHADOWS);
  314. }
  315. set castShadows(value) {
  316. if (hasFlag(this, Flags.CAST_SHADOWS) !== value) {
  317. setFlag(this, Flags.CAST_SHADOWS, value);
  318. this.dirty = true;
  319. }
  320. }
  321. /**
  322. * Whether this command should receive shadows when shadowing is enabled.
  323. *
  324. * @type {boolean}
  325. * @default false
  326. */
  327. get receiveShadows() {
  328. return hasFlag(this, Flags.RECEIVE_SHADOWS);
  329. }
  330. set receiveShadows(value) {
  331. if (hasFlag(this, Flags.RECEIVE_SHADOWS) !== value) {
  332. setFlag(this, Flags.RECEIVE_SHADOWS, value);
  333. this.dirty = true;
  334. }
  335. }
  336. /**
  337. * An object with functions whose names match the uniforms in the shader program
  338. * and return values to set those uniforms.
  339. *
  340. * @type {object}
  341. * @default undefined
  342. */
  343. get uniformMap() {
  344. return this._uniformMap;
  345. }
  346. set uniformMap(value) {
  347. if (this._uniformMap !== value) {
  348. this._uniformMap = value;
  349. this.dirty = true;
  350. }
  351. }
  352. /**
  353. * The render state.
  354. *
  355. * @type {RenderState}
  356. * @default undefined
  357. */
  358. get renderState() {
  359. return this._renderState;
  360. }
  361. set renderState(value) {
  362. if (this._renderState !== value) {
  363. this._renderState = value;
  364. this.dirty = true;
  365. }
  366. }
  367. /**
  368. * The framebuffer to draw to.
  369. *
  370. * @type {Framebuffer}
  371. * @default undefined
  372. */
  373. get framebuffer() {
  374. return this._framebuffer;
  375. }
  376. set framebuffer(value) {
  377. if (this._framebuffer !== value) {
  378. this._framebuffer = value;
  379. this.dirty = true;
  380. }
  381. }
  382. /**
  383. * The pass when to render.
  384. *
  385. * @type {Pass}
  386. * @default undefined
  387. */
  388. get pass() {
  389. return this._pass;
  390. }
  391. set pass(value) {
  392. if (this._pass !== value) {
  393. this._pass = value;
  394. this.dirty = true;
  395. }
  396. }
  397. /**
  398. * Specifies if this command is only to be executed in the frustum closest
  399. * to the eye containing the bounding volume. Defaults to <code>false</code>.
  400. *
  401. * @type {boolean}
  402. * @default false
  403. */
  404. get executeInClosestFrustum() {
  405. return hasFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM);
  406. }
  407. set executeInClosestFrustum(value) {
  408. if (hasFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM) !== value) {
  409. setFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM, value);
  410. this.dirty = true;
  411. }
  412. }
  413. /**
  414. * The object who created this command. This is useful for debugging command
  415. * execution; it allows us to see who created a command when we only have a
  416. * reference to the command, and can be used to selectively execute commands
  417. * with {@link Scene#debugCommandFilter}.
  418. *
  419. * @type {object}
  420. * @default undefined
  421. *
  422. * @see Scene#debugCommandFilter
  423. */
  424. get owner() {
  425. return this._owner;
  426. }
  427. set owner(value) {
  428. if (this._owner !== value) {
  429. this._owner = value;
  430. this.dirty = true;
  431. }
  432. }
  433. /**
  434. * This property is for debugging only; it is not for production use nor is it optimized.
  435. * <p>
  436. * Draws the {@link DrawCommand#boundingVolume} for this command, assuming it is a sphere, when the command executes.
  437. * </p>
  438. *
  439. * @type {boolean}
  440. * @default false
  441. *
  442. * @see DrawCommand#boundingVolume
  443. */
  444. get debugShowBoundingVolume() {
  445. return hasFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME);
  446. }
  447. set debugShowBoundingVolume(value) {
  448. if (hasFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME) !== value) {
  449. setFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME, value);
  450. this.dirty = true;
  451. }
  452. }
  453. /**
  454. * Used to implement Scene.debugShowFrustums.
  455. * @ignore
  456. */
  457. get debugOverlappingFrustums() {
  458. return this._debugOverlappingFrustums;
  459. }
  460. set debugOverlappingFrustums(value) {
  461. if (this._debugOverlappingFrustums !== value) {
  462. this._debugOverlappingFrustums = value;
  463. this.dirty = true;
  464. }
  465. }
  466. /**
  467. * A GLSL string that will evaluate to a pick id. When <code>undefined</code>, the command will only draw depth
  468. * during the pick pass.
  469. *
  470. * @type {string|undefined}
  471. * @default undefined
  472. */
  473. get pickId() {
  474. return this._pickId;
  475. }
  476. set pickId(value) {
  477. if (this._pickId !== value) {
  478. this._pickId = value;
  479. this.dirty = true;
  480. }
  481. }
  482. /**
  483. * Whether metadata picking is allowed.
  484. *
  485. * This is essentially only set to `true` for draw commands that are
  486. * part of a `ModelDrawCommand`, to check whether a derived command
  487. * for metadata picking has to be created.
  488. *
  489. * @type {boolean}
  490. * @default undefined
  491. * @private
  492. */
  493. get pickMetadataAllowed() {
  494. return this._pickMetadataAllowed;
  495. }
  496. /**
  497. * Information about picked metadata.
  498. *
  499. * @type {PickedMetadataInfo|undefined}
  500. * @default undefined
  501. */
  502. get pickedMetadataInfo() {
  503. return this._pickedMetadataInfo;
  504. }
  505. set pickedMetadataInfo(value) {
  506. if (this._pickedMetadataInfo !== value) {
  507. this._pickedMetadataInfo = value;
  508. this.dirty = true;
  509. }
  510. }
  511. /**
  512. * Whether this command should be executed in the pick pass only.
  513. *
  514. * @type {boolean}
  515. * @default false
  516. */
  517. get pickOnly() {
  518. return hasFlag(this, Flags.PICK_ONLY);
  519. }
  520. set pickOnly(value) {
  521. if (hasFlag(this, Flags.PICK_ONLY) !== value) {
  522. setFlag(this, Flags.PICK_ONLY, value);
  523. this.dirty = true;
  524. }
  525. }
  526. /**
  527. * Whether this command should be derived to draw depth for classification of translucent primitives.
  528. *
  529. * @type {boolean}
  530. * @default false
  531. */
  532. get depthForTranslucentClassification() {
  533. return hasFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION);
  534. }
  535. set depthForTranslucentClassification(value) {
  536. if (hasFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION) !== value) {
  537. setFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION, value);
  538. this.dirty = true;
  539. }
  540. }
  541. /**
  542. * @param {DrawCommand} command
  543. * @param {DrawCommand} result
  544. * @returns {DrawCommand}
  545. * @private
  546. */
  547. static shallowClone(command, result) {
  548. if (!defined(command)) {
  549. return undefined;
  550. }
  551. if (!defined(result)) {
  552. result = new DrawCommand();
  553. }
  554. result._boundingVolume = command._boundingVolume;
  555. result._orientedBoundingBox = command._orientedBoundingBox;
  556. result._modelMatrix = command._modelMatrix;
  557. result._primitiveType = command._primitiveType;
  558. result._vertexArray = command._vertexArray;
  559. result._count = command._count;
  560. result._offset = command._offset;
  561. result._instanceCount = command._instanceCount;
  562. result._shaderProgram = command._shaderProgram;
  563. result._uniformMap = command._uniformMap;
  564. result._renderState = command._renderState;
  565. result._framebuffer = command._framebuffer;
  566. result._pass = command._pass;
  567. result._owner = command._owner;
  568. result._debugOverlappingFrustums = command._debugOverlappingFrustums;
  569. result._pickId = command._pickId;
  570. result._pickMetadataAllowed = command._pickMetadataAllowed;
  571. result._pickedMetadataInfo = command._pickedMetadataInfo;
  572. result._flags = command._flags;
  573. result.dirty = true;
  574. result.lastDirtyTime = 0;
  575. return result;
  576. }
  577. /**
  578. * Executes the draw command.
  579. *
  580. * @param {Context} context The renderer context in which to draw.
  581. * @param {PassState} [passState] The state for the current render pass.
  582. */
  583. execute(context, passState) {
  584. context.draw(this, passState);
  585. }
  586. }
  587. /**
  588. * @param {DrawCommand} command
  589. * @param {Flags} flag
  590. * @returns {boolean}
  591. * @ignore
  592. */
  593. function hasFlag(command, flag) {
  594. return (command._flags & flag) === flag;
  595. }
  596. /**
  597. * @param {DrawCommand} command
  598. * @param {Flags} flag
  599. * @param {boolean} value
  600. * @ignore
  601. */
  602. function setFlag(command, flag, value) {
  603. if (value) {
  604. command._flags |= flag;
  605. } else {
  606. command._flags &= ~flag;
  607. }
  608. }
  609. export default DrawCommand;