Primitive.js 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178
  1. import BoundingSphere from '../Core/BoundingSphere.js';
  2. import Cartesian2 from '../Core/Cartesian2.js';
  3. import Cartesian3 from '../Core/Cartesian3.js';
  4. import Cartesian4 from '../Core/Cartesian4.js';
  5. import Cartographic from '../Core/Cartographic.js';
  6. import clone from '../Core/clone.js';
  7. import Color from '../Core/Color.js';
  8. import combine from '../Core/combine.js';
  9. import ComponentDatatype from '../Core/ComponentDatatype.js';
  10. import defaultValue from '../Core/defaultValue.js';
  11. import defined from '../Core/defined.js';
  12. import defineProperties from '../Core/defineProperties.js';
  13. import destroyObject from '../Core/destroyObject.js';
  14. import DeveloperError from '../Core/DeveloperError.js';
  15. import EncodedCartesian3 from '../Core/EncodedCartesian3.js';
  16. import FeatureDetection from '../Core/FeatureDetection.js';
  17. import Geometry from '../Core/Geometry.js';
  18. import GeometryAttribute from '../Core/GeometryAttribute.js';
  19. import GeometryAttributes from '../Core/GeometryAttributes.js';
  20. import GeometryOffsetAttribute from '../Core/GeometryOffsetAttribute.js';
  21. import Intersect from '../Core/Intersect.js';
  22. import isArray from '../Core/isArray.js';
  23. import Matrix4 from '../Core/Matrix4.js';
  24. import Plane from '../Core/Plane.js';
  25. import RuntimeError from '../Core/RuntimeError.js';
  26. import subdivideArray from '../Core/subdivideArray.js';
  27. import TaskProcessor from '../Core/TaskProcessor.js';
  28. import BufferUsage from '../Renderer/BufferUsage.js';
  29. import ContextLimits from '../Renderer/ContextLimits.js';
  30. import DrawCommand from '../Renderer/DrawCommand.js';
  31. import Pass from '../Renderer/Pass.js';
  32. import RenderState from '../Renderer/RenderState.js';
  33. import ShaderProgram from '../Renderer/ShaderProgram.js';
  34. import ShaderSource from '../Renderer/ShaderSource.js';
  35. import VertexArray from '../Renderer/VertexArray.js';
  36. import when from '../ThirdParty/when.js';
  37. import BatchTable from './BatchTable.js';
  38. import CullFace from './CullFace.js';
  39. import DepthFunction from './DepthFunction.js';
  40. import PrimitivePipeline from './PrimitivePipeline.js';
  41. import PrimitiveState from './PrimitiveState.js';
  42. import SceneMode from './SceneMode.js';
  43. import ShadowMode from './ShadowMode.js';
  44. /**
  45. * A primitive represents geometry in the {@link Scene}. The geometry can be from a single {@link GeometryInstance}
  46. * as shown in example 1 below, or from an array of instances, even if the geometry is from different
  47. * geometry types, e.g., an {@link RectangleGeometry} and an {@link EllipsoidGeometry} as shown in Code Example 2.
  48. * <p>
  49. * A primitive combines geometry instances with an {@link Appearance} that describes the full shading, including
  50. * {@link Material} and {@link RenderState}. Roughly, the geometry instance defines the structure and placement,
  51. * and the appearance defines the visual characteristics. Decoupling geometry and appearance allows us to mix
  52. * and match most of them and add a new geometry or appearance independently of each other.
  53. * </p>
  54. * <p>
  55. * Combining multiple instances into one primitive is called batching, and significantly improves performance for static data.
  56. * Instances can be individually picked; {@link Scene#pick} returns their {@link GeometryInstance#id}. Using
  57. * per-instance appearances like {@link PerInstanceColorAppearance}, each instance can also have a unique color.
  58. * </p>
  59. * <p>
  60. * {@link Geometry} can either be created and batched on a web worker or the main thread. The first two examples
  61. * show geometry that will be created on a web worker by using the descriptions of the geometry. The third example
  62. * shows how to create the geometry on the main thread by explicitly calling the <code>createGeometry</code> method.
  63. * </p>
  64. *
  65. * @alias Primitive
  66. * @constructor
  67. *
  68. * @param {Object} [options] Object with the following properties:
  69. * @param {GeometryInstance[]|GeometryInstance} [options.geometryInstances] The geometry instances - or a single geometry instance - to render.
  70. * @param {Appearance} [options.appearance] The appearance used to render the primitive.
  71. * @param {Appearance} [options.depthFailAppearance] The appearance used to shade this primitive when it fails the depth test.
  72. * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
  73. * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
  74. * @param {Boolean} [options.vertexCacheOptimize=false] When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  75. * @param {Boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
  76. * @param {Boolean} [options.compressVertices=true] When <code>true</code>, the geometry vertices are compressed, which will save memory.
  77. * @param {Boolean} [options.releaseGeometryInstances=true] When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  78. * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
  79. * @param {Boolean} [options.cull=true] When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands based on their bounding volume. Set this to <code>false</code> for a small performance gain if you are manually culling the primitive.
  80. * @param {Boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready.
  81. * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
  82. * @param {ShadowMode} [options.shadows=ShadowMode.DISABLED] Determines whether this primitive casts or receives shadows from each light source.
  83. *
  84. * @example
  85. * // 1. Draw a translucent ellipse on the surface with a checkerboard pattern
  86. * var instance = new Cesium.GeometryInstance({
  87. * geometry : new Cesium.EllipseGeometry({
  88. * center : Cesium.Cartesian3.fromDegrees(-100.0, 20.0),
  89. * semiMinorAxis : 500000.0,
  90. * semiMajorAxis : 1000000.0,
  91. * rotation : Cesium.Math.PI_OVER_FOUR,
  92. * vertexFormat : Cesium.VertexFormat.POSITION_AND_ST
  93. * }),
  94. * id : 'object returned when this instance is picked and to get/set per-instance attributes'
  95. * });
  96. * scene.primitives.add(new Cesium.Primitive({
  97. * geometryInstances : instance,
  98. * appearance : new Cesium.EllipsoidSurfaceAppearance({
  99. * material : Cesium.Material.fromType('Checkerboard')
  100. * })
  101. * }));
  102. *
  103. * @example
  104. * // 2. Draw different instances each with a unique color
  105. * var rectangleInstance = new Cesium.GeometryInstance({
  106. * geometry : new Cesium.RectangleGeometry({
  107. * rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0),
  108. * vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  109. * }),
  110. * id : 'rectangle',
  111. * attributes : {
  112. * color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
  113. * }
  114. * });
  115. * var ellipsoidInstance = new Cesium.GeometryInstance({
  116. * geometry : new Cesium.EllipsoidGeometry({
  117. * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
  118. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
  119. * }),
  120. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  121. * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
  122. * id : 'ellipsoid',
  123. * attributes : {
  124. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  125. * }
  126. * });
  127. * scene.primitives.add(new Cesium.Primitive({
  128. * geometryInstances : [rectangleInstance, ellipsoidInstance],
  129. * appearance : new Cesium.PerInstanceColorAppearance()
  130. * }));
  131. *
  132. * @example
  133. * // 3. Create the geometry on the main thread.
  134. * scene.primitives.add(new Cesium.Primitive({
  135. * geometryInstances : new Cesium.GeometryInstance({
  136. * geometry : Cesium.EllipsoidGeometry.createGeometry(new Cesium.EllipsoidGeometry({
  137. * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
  138. * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
  139. * })),
  140. * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
  141. * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
  142. * id : 'ellipsoid',
  143. * attributes : {
  144. * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
  145. * }
  146. * }),
  147. * appearance : new Cesium.PerInstanceColorAppearance()
  148. * }));
  149. *
  150. * @see GeometryInstance
  151. * @see Appearance
  152. * @see ClassificationPrimitive
  153. * @see GroundPrimitive
  154. */
  155. function Primitive(options) {
  156. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  157. /**
  158. * The geometry instances rendered with this primitive. This may
  159. * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
  160. * is <code>true</code> when the primitive is constructed.
  161. * <p>
  162. * Changing this property after the primitive is rendered has no effect.
  163. * </p>
  164. *
  165. * @readonly
  166. * @type GeometryInstance[]|GeometryInstance
  167. *
  168. * @default undefined
  169. */
  170. this.geometryInstances = options.geometryInstances;
  171. /**
  172. * The {@link Appearance} used to shade this primitive. Each geometry
  173. * instance is shaded with the same appearance. Some appearances, like
  174. * {@link PerInstanceColorAppearance} allow giving each instance unique
  175. * properties.
  176. *
  177. * @type Appearance
  178. *
  179. * @default undefined
  180. */
  181. this.appearance = options.appearance;
  182. this._appearance = undefined;
  183. this._material = undefined;
  184. /**
  185. * The {@link Appearance} used to shade this primitive when it fails the depth test. Each geometry
  186. * instance is shaded with the same appearance. Some appearances, like
  187. * {@link PerInstanceColorAppearance} allow giving each instance unique
  188. * properties.
  189. *
  190. * <p>
  191. * When using an appearance that requires a color attribute, like PerInstanceColorAppearance,
  192. * add a depthFailColor per-instance attribute instead.
  193. * </p>
  194. *
  195. * <p>
  196. * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported,
  197. * there may be artifacts.
  198. * </p>
  199. * @type Appearance
  200. *
  201. * @default undefined
  202. */
  203. this.depthFailAppearance = options.depthFailAppearance;
  204. this._depthFailAppearance = undefined;
  205. this._depthFailMaterial = undefined;
  206. /**
  207. * The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
  208. * When this is the identity matrix, the primitive is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
  209. * Local reference frames can be used by providing a different transformation matrix, like that returned
  210. * by {@link Transforms.eastNorthUpToFixedFrame}.
  211. *
  212. * <p>
  213. * This property is only supported in 3D mode.
  214. * </p>
  215. *
  216. * @type Matrix4
  217. *
  218. * @default Matrix4.IDENTITY
  219. *
  220. * @example
  221. * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
  222. * p.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
  223. */
  224. this.modelMatrix = Matrix4.clone(defaultValue(options.modelMatrix, Matrix4.IDENTITY));
  225. this._modelMatrix = new Matrix4();
  226. /**
  227. * Determines if the primitive will be shown. This affects all geometry
  228. * instances in the primitive.
  229. *
  230. * @type Boolean
  231. *
  232. * @default true
  233. */
  234. this.show = defaultValue(options.show, true);
  235. this._vertexCacheOptimize = defaultValue(options.vertexCacheOptimize, false);
  236. this._interleave = defaultValue(options.interleave, false);
  237. this._releaseGeometryInstances = defaultValue(options.releaseGeometryInstances, true);
  238. this._allowPicking = defaultValue(options.allowPicking, true);
  239. this._asynchronous = defaultValue(options.asynchronous, true);
  240. this._compressVertices = defaultValue(options.compressVertices, true);
  241. /**
  242. * When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands
  243. * based on their bounding volume. Set this to <code>false</code> for a small performance gain
  244. * if you are manually culling the primitive.
  245. *
  246. * @type {Boolean}
  247. *
  248. * @default true
  249. */
  250. this.cull = defaultValue(options.cull, true);
  251. /**
  252. * This property is for debugging only; it is not for production use nor is it optimized.
  253. * <p>
  254. * Draws the bounding sphere for each draw command in the primitive.
  255. * </p>
  256. *
  257. * @type {Boolean}
  258. *
  259. * @default false
  260. */
  261. this.debugShowBoundingVolume = defaultValue(options.debugShowBoundingVolume, false);
  262. /**
  263. * @private
  264. */
  265. this.rtcCenter = options.rtcCenter;
  266. //>>includeStart('debug', pragmas.debug);
  267. if (defined(this.rtcCenter) && (!defined(this.geometryInstances) || (isArray(this.geometryInstances) && this.geometryInstances.length !== 1))) {
  268. throw new DeveloperError('Relative-to-center rendering only supports one geometry instance.');
  269. }
  270. //>>includeEnd('debug');
  271. /**
  272. * Determines whether this primitive casts or receives shadows from each light source.
  273. *
  274. * @type {ShadowMode}
  275. *
  276. * @default ShadowMode.DISABLED
  277. */
  278. this.shadows = defaultValue(options.shadows, ShadowMode.DISABLED);
  279. this._translucent = undefined;
  280. this._state = PrimitiveState.READY;
  281. this._geometries = [];
  282. this._error = undefined;
  283. this._numberOfInstances = 0;
  284. this._boundingSpheres = [];
  285. this._boundingSphereWC = [];
  286. this._boundingSphereCV = [];
  287. this._boundingSphere2D = [];
  288. this._boundingSphereMorph = [];
  289. this._perInstanceAttributeCache = [];
  290. this._instanceIds = [];
  291. this._lastPerInstanceAttributeIndex = 0;
  292. this._va = [];
  293. this._attributeLocations = undefined;
  294. this._primitiveType = undefined;
  295. this._frontFaceRS = undefined;
  296. this._backFaceRS = undefined;
  297. this._sp = undefined;
  298. this._depthFailAppearance = undefined;
  299. this._spDepthFail = undefined;
  300. this._frontFaceDepthFailRS = undefined;
  301. this._backFaceDepthFailRS = undefined;
  302. this._pickIds = [];
  303. this._colorCommands = [];
  304. this._pickCommands = [];
  305. this._readOnlyInstanceAttributes = options._readOnlyInstanceAttributes;
  306. this._createBoundingVolumeFunction = options._createBoundingVolumeFunction;
  307. this._createRenderStatesFunction = options._createRenderStatesFunction;
  308. this._createShaderProgramFunction = options._createShaderProgramFunction;
  309. this._createCommandsFunction = options._createCommandsFunction;
  310. this._updateAndQueueCommandsFunction = options._updateAndQueueCommandsFunction;
  311. this._createPickOffsets = options._createPickOffsets;
  312. this._pickOffsets = undefined;
  313. this._createGeometryResults = undefined;
  314. this._ready = false;
  315. this._readyPromise = when.defer();
  316. this._batchTable = undefined;
  317. this._batchTableAttributeIndices = undefined;
  318. this._offsetInstanceExtend = undefined;
  319. this._batchTableOffsetAttribute2DIndex = undefined;
  320. this._batchTableOffsetsUpdated = false;
  321. this._instanceBoundingSpheres = undefined;
  322. this._instanceBoundingSpheresCV = undefined;
  323. this._tempBoundingSpheres = undefined;
  324. this._recomputeBoundingSpheres = false;
  325. this._batchTableBoundingSpheresUpdated = false;
  326. this._batchTableBoundingSphereAttributeIndices = undefined;
  327. }
  328. defineProperties(Primitive.prototype, {
  329. /**
  330. * When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
  331. *
  332. * @memberof Primitive.prototype
  333. *
  334. * @type {Boolean}
  335. * @readonly
  336. *
  337. * @default true
  338. */
  339. vertexCacheOptimize : {
  340. get : function() {
  341. return this._vertexCacheOptimize;
  342. }
  343. },
  344. /**
  345. * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
  346. *
  347. * @memberof Primitive.prototype
  348. *
  349. * @type {Boolean}
  350. * @readonly
  351. *
  352. * @default false
  353. */
  354. interleave : {
  355. get : function() {
  356. return this._interleave;
  357. }
  358. },
  359. /**
  360. * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
  361. *
  362. * @memberof Primitive.prototype
  363. *
  364. * @type {Boolean}
  365. * @readonly
  366. *
  367. * @default true
  368. */
  369. releaseGeometryInstances : {
  370. get : function() {
  371. return this._releaseGeometryInstances;
  372. }
  373. },
  374. /**
  375. * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved. *
  376. *
  377. * @memberof Primitive.prototype
  378. *
  379. * @type {Boolean}
  380. * @readonly
  381. *
  382. * @default true
  383. */
  384. allowPicking : {
  385. get : function() {
  386. return this._allowPicking;
  387. }
  388. },
  389. /**
  390. * Determines if the geometry instances will be created and batched on a web worker.
  391. *
  392. * @memberof Primitive.prototype
  393. *
  394. * @type {Boolean}
  395. * @readonly
  396. *
  397. * @default true
  398. */
  399. asynchronous : {
  400. get : function() {
  401. return this._asynchronous;
  402. }
  403. },
  404. /**
  405. * When <code>true</code>, geometry vertices are compressed, which will save memory.
  406. *
  407. * @memberof Primitive.prototype
  408. *
  409. * @type {Boolean}
  410. * @readonly
  411. *
  412. * @default true
  413. */
  414. compressVertices : {
  415. get : function() {
  416. return this._compressVertices;
  417. }
  418. },
  419. /**
  420. * Determines if the primitive is complete and ready to render. If this property is
  421. * true, the primitive will be rendered the next time that {@link Primitive#update}
  422. * is called.
  423. *
  424. * @memberof Primitive.prototype
  425. *
  426. * @type {Boolean}
  427. * @readonly
  428. */
  429. ready : {
  430. get : function() {
  431. return this._ready;
  432. }
  433. },
  434. /**
  435. * Gets a promise that resolves when the primitive is ready to render.
  436. * @memberof Primitive.prototype
  437. * @type {Promise.<Primitive>}
  438. * @readonly
  439. */
  440. readyPromise : {
  441. get : function() {
  442. return this._readyPromise.promise;
  443. }
  444. }
  445. });
  446. function getCommonPerInstanceAttributeNames(instances) {
  447. var length = instances.length;
  448. var attributesInAllInstances = [];
  449. var attributes0 = instances[0].attributes;
  450. var name;
  451. for (name in attributes0) {
  452. if (attributes0.hasOwnProperty(name) && defined(attributes0[name])) {
  453. var attribute = attributes0[name];
  454. var inAllInstances = true;
  455. // Does this same attribute exist in all instances?
  456. for (var i = 1; i < length; ++i) {
  457. var otherAttribute = instances[i].attributes[name];
  458. if (!defined(otherAttribute) ||
  459. (attribute.componentDatatype !== otherAttribute.componentDatatype) ||
  460. (attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute) ||
  461. (attribute.normalize !== otherAttribute.normalize)) {
  462. inAllInstances = false;
  463. break;
  464. }
  465. }
  466. if (inAllInstances) {
  467. attributesInAllInstances.push(name);
  468. }
  469. }
  470. }
  471. return attributesInAllInstances;
  472. }
  473. var scratchGetAttributeCartesian2 = new Cartesian2();
  474. var scratchGetAttributeCartesian3 = new Cartesian3();
  475. var scratchGetAttributeCartesian4 = new Cartesian4();
  476. function getAttributeValue(value) {
  477. var componentsPerAttribute = value.length;
  478. if (componentsPerAttribute === 1) {
  479. return value[0];
  480. } else if (componentsPerAttribute === 2) {
  481. return Cartesian2.unpack(value, 0, scratchGetAttributeCartesian2);
  482. } else if (componentsPerAttribute === 3) {
  483. return Cartesian3.unpack(value, 0, scratchGetAttributeCartesian3);
  484. } else if (componentsPerAttribute === 4) {
  485. return Cartesian4.unpack(value, 0, scratchGetAttributeCartesian4);
  486. }
  487. }
  488. function createBatchTable(primitive, context) {
  489. var geometryInstances = primitive.geometryInstances;
  490. var instances = (isArray(geometryInstances)) ? geometryInstances : [geometryInstances];
  491. var numberOfInstances = instances.length;
  492. if (numberOfInstances === 0) {
  493. return;
  494. }
  495. var names = getCommonPerInstanceAttributeNames(instances);
  496. var length = names.length;
  497. var attributes = [];
  498. var attributeIndices = {};
  499. var boundingSphereAttributeIndices = {};
  500. var offset2DIndex;
  501. var firstInstance = instances[0];
  502. var instanceAttributes = firstInstance.attributes;
  503. var i;
  504. var name;
  505. var attribute;
  506. for (i = 0; i < length; ++i) {
  507. name = names[i];
  508. attribute = instanceAttributes[name];
  509. attributeIndices[name] = i;
  510. attributes.push({
  511. functionName : 'czm_batchTable_' + name,
  512. componentDatatype : attribute.componentDatatype,
  513. componentsPerAttribute : attribute.componentsPerAttribute,
  514. normalize : attribute.normalize
  515. });
  516. }
  517. if (names.indexOf('distanceDisplayCondition') !== -1) {
  518. attributes.push({
  519. functionName : 'czm_batchTable_boundingSphereCenter3DHigh',
  520. componentDatatype : ComponentDatatype.FLOAT,
  521. componentsPerAttribute : 3
  522. }, {
  523. functionName : 'czm_batchTable_boundingSphereCenter3DLow',
  524. componentDatatype : ComponentDatatype.FLOAT,
  525. componentsPerAttribute : 3
  526. }, {
  527. functionName : 'czm_batchTable_boundingSphereCenter2DHigh',
  528. componentDatatype : ComponentDatatype.FLOAT,
  529. componentsPerAttribute : 3
  530. }, {
  531. functionName : 'czm_batchTable_boundingSphereCenter2DLow',
  532. componentDatatype : ComponentDatatype.FLOAT,
  533. componentsPerAttribute : 3
  534. }, {
  535. functionName : 'czm_batchTable_boundingSphereRadius',
  536. componentDatatype : ComponentDatatype.FLOAT,
  537. componentsPerAttribute : 1
  538. });
  539. boundingSphereAttributeIndices.center3DHigh = attributes.length - 5;
  540. boundingSphereAttributeIndices.center3DLow = attributes.length - 4;
  541. boundingSphereAttributeIndices.center2DHigh = attributes.length - 3;
  542. boundingSphereAttributeIndices.center2DLow = attributes.length - 2;
  543. boundingSphereAttributeIndices.radius = attributes.length - 1;
  544. }
  545. if (names.indexOf('offset') !== -1) {
  546. attributes.push({
  547. functionName : 'czm_batchTable_offset2D',
  548. componentDatatype : ComponentDatatype.FLOAT,
  549. componentsPerAttribute : 3
  550. });
  551. offset2DIndex = attributes.length - 1;
  552. }
  553. attributes.push({
  554. functionName : 'czm_batchTable_pickColor',
  555. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  556. componentsPerAttribute : 4,
  557. normalize : true
  558. });
  559. var attributesLength = attributes.length;
  560. var batchTable = new BatchTable(context, attributes, numberOfInstances);
  561. for (i = 0; i < numberOfInstances; ++i) {
  562. var instance = instances[i];
  563. instanceAttributes = instance.attributes;
  564. for (var j = 0; j < length; ++j) {
  565. name = names[j];
  566. attribute = instanceAttributes[name];
  567. var value = getAttributeValue(attribute.value);
  568. var attributeIndex = attributeIndices[name];
  569. batchTable.setBatchedAttribute(i, attributeIndex, value);
  570. }
  571. var pickObject = {
  572. primitive : defaultValue(instance.pickPrimitive, primitive)
  573. };
  574. if (defined(instance.id)) {
  575. pickObject.id = instance.id;
  576. }
  577. var pickId = context.createPickId(pickObject);
  578. primitive._pickIds.push(pickId);
  579. var pickColor = pickId.color;
  580. var color = scratchGetAttributeCartesian4;
  581. color.x = Color.floatToByte(pickColor.red);
  582. color.y = Color.floatToByte(pickColor.green);
  583. color.z = Color.floatToByte(pickColor.blue);
  584. color.w = Color.floatToByte(pickColor.alpha);
  585. batchTable.setBatchedAttribute(i, attributesLength - 1, color);
  586. }
  587. primitive._batchTable = batchTable;
  588. primitive._batchTableAttributeIndices = attributeIndices;
  589. primitive._batchTableBoundingSphereAttributeIndices = boundingSphereAttributeIndices;
  590. primitive._batchTableOffsetAttribute2DIndex = offset2DIndex;
  591. }
  592. function cloneAttribute(attribute) {
  593. var clonedValues;
  594. if (isArray(attribute.values)) {
  595. clonedValues = attribute.values.slice(0);
  596. } else {
  597. clonedValues = new attribute.values.constructor(attribute.values);
  598. }
  599. return new GeometryAttribute({
  600. componentDatatype : attribute.componentDatatype,
  601. componentsPerAttribute : attribute.componentsPerAttribute,
  602. normalize : attribute.normalize,
  603. values : clonedValues
  604. });
  605. }
  606. function cloneGeometry(geometry) {
  607. var attributes = geometry.attributes;
  608. var newAttributes = new GeometryAttributes();
  609. for (var property in attributes) {
  610. if (attributes.hasOwnProperty(property) && defined(attributes[property])) {
  611. newAttributes[property] = cloneAttribute(attributes[property]);
  612. }
  613. }
  614. var indices;
  615. if (defined(geometry.indices)) {
  616. var sourceValues = geometry.indices;
  617. if (isArray(sourceValues)) {
  618. indices = sourceValues.slice(0);
  619. } else {
  620. indices = new sourceValues.constructor(sourceValues);
  621. }
  622. }
  623. return new Geometry({
  624. attributes : newAttributes,
  625. indices : indices,
  626. primitiveType : geometry.primitiveType,
  627. boundingSphere : BoundingSphere.clone(geometry.boundingSphere)
  628. });
  629. }
  630. function cloneInstance(instance, geometry) {
  631. return {
  632. geometry : geometry,
  633. attributes: instance.attributes,
  634. modelMatrix : Matrix4.clone(instance.modelMatrix),
  635. pickPrimitive : instance.pickPrimitive,
  636. id : instance.id
  637. };
  638. }
  639. var positionRegex = /attribute\s+vec(?:3|4)\s+(.*)3DHigh;/g;
  640. Primitive._modifyShaderPosition = function(primitive, vertexShaderSource, scene3DOnly) {
  641. var match;
  642. var forwardDecl = '';
  643. var attributes = '';
  644. var computeFunctions = '';
  645. while ((match = positionRegex.exec(vertexShaderSource)) !== null) {
  646. var name = match[1];
  647. var functionName = 'vec4 czm_compute' + name[0].toUpperCase() + name.substr(1) + '()';
  648. // Don't forward-declare czm_computePosition because computePosition.glsl already does.
  649. if (functionName !== 'vec4 czm_computePosition()') {
  650. forwardDecl += functionName + ';\n';
  651. }
  652. if (!defined(primitive.rtcCenter)) {
  653. // Use GPU RTE
  654. if (!scene3DOnly) {
  655. attributes +=
  656. 'attribute vec3 ' + name + '2DHigh;\n' +
  657. 'attribute vec3 ' + name + '2DLow;\n';
  658. computeFunctions +=
  659. functionName + '\n' +
  660. '{\n' +
  661. ' vec4 p;\n' +
  662. ' if (czm_morphTime == 1.0)\n' +
  663. ' {\n' +
  664. ' p = czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow);\n' +
  665. ' }\n' +
  666. ' else if (czm_morphTime == 0.0)\n' +
  667. ' {\n' +
  668. ' p = czm_translateRelativeToEye(' + name + '2DHigh.zxy, ' + name + '2DLow.zxy);\n' +
  669. ' }\n' +
  670. ' else\n' +
  671. ' {\n' +
  672. ' p = czm_columbusViewMorph(\n' +
  673. ' czm_translateRelativeToEye(' + name + '2DHigh.zxy, ' + name + '2DLow.zxy),\n' +
  674. ' czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow),\n' +
  675. ' czm_morphTime);\n' +
  676. ' }\n' +
  677. ' return p;\n' +
  678. '}\n\n';
  679. } else {
  680. computeFunctions +=
  681. functionName + '\n' +
  682. '{\n' +
  683. ' return czm_translateRelativeToEye(' + name + '3DHigh, ' + name + '3DLow);\n' +
  684. '}\n\n';
  685. }
  686. } else {
  687. // Use RTC
  688. vertexShaderSource = vertexShaderSource.replace(/attribute\s+vec(?:3|4)\s+position3DHigh;/g, '');
  689. vertexShaderSource = vertexShaderSource.replace(/attribute\s+vec(?:3|4)\s+position3DLow;/g, '');
  690. forwardDecl += 'uniform mat4 u_modifiedModelView;\n';
  691. attributes += 'attribute vec4 position;\n';
  692. computeFunctions +=
  693. functionName + '\n' +
  694. '{\n' +
  695. ' return u_modifiedModelView * position;\n' +
  696. '}\n\n';
  697. vertexShaderSource = vertexShaderSource.replace(/czm_modelViewRelativeToEye\s+\*\s+/g, '');
  698. vertexShaderSource = vertexShaderSource.replace(/czm_modelViewProjectionRelativeToEye/g, 'czm_projection');
  699. }
  700. }
  701. return [forwardDecl, attributes, vertexShaderSource, computeFunctions].join('\n');
  702. };
  703. Primitive._appendShowToShader = function(primitive, vertexShaderSource) {
  704. if (!defined(primitive._batchTableAttributeIndices.show)) {
  705. return vertexShaderSource;
  706. }
  707. var renamedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_show_main');
  708. var showMain =
  709. 'void main() \n' +
  710. '{ \n' +
  711. ' czm_non_show_main(); \n' +
  712. ' gl_Position *= czm_batchTable_show(batchId); \n' +
  713. '}';
  714. return renamedVS + '\n' + showMain;
  715. };
  716. Primitive._updateColorAttribute = function(primitive, vertexShaderSource, isDepthFail) {
  717. // some appearances have a color attribute for per vertex color.
  718. // only remove if color is a per instance attribute.
  719. if (!defined(primitive._batchTableAttributeIndices.color) && !defined(primitive._batchTableAttributeIndices.depthFailColor)) {
  720. return vertexShaderSource;
  721. }
  722. if (vertexShaderSource.search(/attribute\s+vec4\s+color;/g) === -1) {
  723. return vertexShaderSource;
  724. }
  725. //>>includeStart('debug', pragmas.debug);
  726. if (isDepthFail && !defined(primitive._batchTableAttributeIndices.depthFailColor)) {
  727. throw new DeveloperError('A depthFailColor per-instance attribute is required when using a depth fail appearance that uses a color attribute.');
  728. }
  729. //>>includeEnd('debug');
  730. var modifiedVS = vertexShaderSource;
  731. modifiedVS = modifiedVS.replace(/attribute\s+vec4\s+color;/g, '');
  732. if (!isDepthFail) {
  733. modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_color(batchId)$2');
  734. } else {
  735. modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_depthFailColor(batchId)$2');
  736. }
  737. return modifiedVS;
  738. };
  739. function appendPickToVertexShader(source) {
  740. var renamedVS = ShaderSource.replaceMain(source, 'czm_non_pick_main');
  741. var pickMain = 'varying vec4 v_pickColor; \n' +
  742. 'void main() \n' +
  743. '{ \n' +
  744. ' czm_non_pick_main(); \n' +
  745. ' v_pickColor = czm_batchTable_pickColor(batchId); \n' +
  746. '}';
  747. return renamedVS + '\n' + pickMain;
  748. }
  749. function appendPickToFragmentShader(source) {
  750. return 'varying vec4 v_pickColor;\n' + source;
  751. }
  752. Primitive._updatePickColorAttribute = function(source) {
  753. var vsPick = source.replace(/attribute\s+vec4\s+pickColor;/g, '');
  754. vsPick = vsPick.replace(/(\b)pickColor(\b)/g, '$1czm_batchTable_pickColor(batchId)$2');
  755. return vsPick;
  756. };
  757. Primitive._appendOffsetToShader = function(primitive, vertexShaderSource) {
  758. if (!defined(primitive._batchTableAttributeIndices.offset)) {
  759. return vertexShaderSource;
  760. }
  761. var attr = 'attribute float batchId;\n';
  762. attr += 'attribute float applyOffset;';
  763. var modifiedShader = vertexShaderSource.replace(/attribute\s+float\s+batchId;/g, attr);
  764. var str = 'vec4 $1 = czm_computePosition();\n';
  765. str += ' if (czm_sceneMode == czm_sceneMode3D)\n';
  766. str += ' {\n';
  767. str += ' $1 = $1 + vec4(czm_batchTable_offset(batchId) * applyOffset, 0.0);';
  768. str += ' }\n';
  769. str += ' else\n';
  770. str += ' {\n';
  771. str += ' $1 = $1 + vec4(czm_batchTable_offset2D(batchId) * applyOffset, 0.0);';
  772. str += ' }\n';
  773. modifiedShader = modifiedShader.replace(/vec4\s+([A-Za-z0-9_]+)\s+=\s+czm_computePosition\(\);/g, str);
  774. return modifiedShader;
  775. };
  776. Primitive._appendDistanceDisplayConditionToShader = function(primitive, vertexShaderSource, scene3DOnly) {
  777. if (!defined(primitive._batchTableAttributeIndices.distanceDisplayCondition)) {
  778. return vertexShaderSource;
  779. }
  780. var renamedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_distanceDisplayCondition_main');
  781. var distanceDisplayConditionMain =
  782. 'void main() \n' +
  783. '{ \n' +
  784. ' czm_non_distanceDisplayCondition_main(); \n' +
  785. ' vec2 distanceDisplayCondition = czm_batchTable_distanceDisplayCondition(batchId);\n' +
  786. ' vec3 boundingSphereCenter3DHigh = czm_batchTable_boundingSphereCenter3DHigh(batchId);\n' +
  787. ' vec3 boundingSphereCenter3DLow = czm_batchTable_boundingSphereCenter3DLow(batchId);\n' +
  788. ' float boundingSphereRadius = czm_batchTable_boundingSphereRadius(batchId);\n';
  789. if (!scene3DOnly) {
  790. distanceDisplayConditionMain +=
  791. ' vec3 boundingSphereCenter2DHigh = czm_batchTable_boundingSphereCenter2DHigh(batchId);\n' +
  792. ' vec3 boundingSphereCenter2DLow = czm_batchTable_boundingSphereCenter2DLow(batchId);\n' +
  793. ' vec4 centerRTE;\n' +
  794. ' if (czm_morphTime == 1.0)\n' +
  795. ' {\n' +
  796. ' centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n' +
  797. ' }\n' +
  798. ' else if (czm_morphTime == 0.0)\n' +
  799. ' {\n' +
  800. ' centerRTE = czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy);\n' +
  801. ' }\n' +
  802. ' else\n' +
  803. ' {\n' +
  804. ' centerRTE = czm_columbusViewMorph(\n' +
  805. ' czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy),\n' +
  806. ' czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow),\n' +
  807. ' czm_morphTime);\n' +
  808. ' }\n';
  809. } else {
  810. distanceDisplayConditionMain +=
  811. ' vec4 centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n';
  812. }
  813. distanceDisplayConditionMain +=
  814. ' float radiusSq = boundingSphereRadius * boundingSphereRadius; \n' +
  815. ' float distanceSq; \n' +
  816. ' if (czm_sceneMode == czm_sceneMode2D) \n' +
  817. ' { \n' +
  818. ' distanceSq = czm_eyeHeight2D.y - radiusSq; \n' +
  819. ' } \n' +
  820. ' else \n' +
  821. ' { \n' +
  822. ' distanceSq = dot(centerRTE.xyz, centerRTE.xyz) - radiusSq; \n' +
  823. ' } \n' +
  824. ' distanceSq = max(distanceSq, 0.0); \n' +
  825. ' float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x; \n' +
  826. ' float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y; \n' +
  827. ' float show = (distanceSq >= nearSq && distanceSq <= farSq) ? 1.0 : 0.0; \n' +
  828. ' gl_Position *= show; \n' +
  829. '}';
  830. return renamedVS + '\n' + distanceDisplayConditionMain;
  831. };
  832. function modifyForEncodedNormals(primitive, vertexShaderSource) {
  833. if (!primitive.compressVertices) {
  834. return vertexShaderSource;
  835. }
  836. var containsNormal = vertexShaderSource.search(/attribute\s+vec3\s+normal;/g) !== -1;
  837. var containsSt = vertexShaderSource.search(/attribute\s+vec2\s+st;/g) !== -1;
  838. if (!containsNormal && !containsSt) {
  839. return vertexShaderSource;
  840. }
  841. var containsTangent = vertexShaderSource.search(/attribute\s+vec3\s+tangent;/g) !== -1;
  842. var containsBitangent = vertexShaderSource.search(/attribute\s+vec3\s+bitangent;/g) !== -1;
  843. var numComponents = containsSt && containsNormal ? 2.0 : 1.0;
  844. numComponents += containsTangent || containsBitangent ? 1 : 0;
  845. var type = (numComponents > 1) ? 'vec' + numComponents : 'float';
  846. var attributeName = 'compressedAttributes';
  847. var attributeDecl = 'attribute ' + type + ' ' + attributeName + ';';
  848. var globalDecl = '';
  849. var decode = '';
  850. if (containsSt) {
  851. globalDecl += 'vec2 st;\n';
  852. var stComponent = numComponents > 1 ? attributeName + '.x' : attributeName;
  853. decode += ' st = czm_decompressTextureCoordinates(' + stComponent + ');\n';
  854. }
  855. if (containsNormal && containsTangent && containsBitangent) {
  856. globalDecl +=
  857. 'vec3 normal;\n' +
  858. 'vec3 tangent;\n' +
  859. 'vec3 bitangent;\n';
  860. decode += ' czm_octDecode(' + attributeName + '.' + (containsSt ? 'yz' : 'xy') + ', normal, tangent, bitangent);\n';
  861. } else {
  862. if (containsNormal) {
  863. globalDecl += 'vec3 normal;\n';
  864. decode += ' normal = czm_octDecode(' + attributeName + (numComponents > 1 ? '.' + (containsSt ? 'y' : 'x') : '') + ');\n';
  865. }
  866. if (containsTangent) {
  867. globalDecl += 'vec3 tangent;\n';
  868. decode += ' tangent = czm_octDecode(' + attributeName + '.' + (containsSt && containsNormal ? 'z' : 'y') + ');\n';
  869. }
  870. if (containsBitangent) {
  871. globalDecl += 'vec3 bitangent;\n';
  872. decode += ' bitangent = czm_octDecode(' + attributeName + '.' + (containsSt && containsNormal ? 'z' : 'y') + ');\n';
  873. }
  874. }
  875. var modifiedVS = vertexShaderSource;
  876. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+normal;/g, '');
  877. modifiedVS = modifiedVS.replace(/attribute\s+vec2\s+st;/g, '');
  878. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+tangent;/g, '');
  879. modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+bitangent;/g, '');
  880. modifiedVS = ShaderSource.replaceMain(modifiedVS, 'czm_non_compressed_main');
  881. var compressedMain =
  882. 'void main() \n' +
  883. '{ \n' +
  884. decode +
  885. ' czm_non_compressed_main(); \n' +
  886. '}';
  887. return [attributeDecl, globalDecl, modifiedVS, compressedMain].join('\n');
  888. }
  889. function depthClampVS(vertexShaderSource) {
  890. var modifiedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_depth_clamp_main');
  891. // The varying should be surround by #ifdef GL_EXT_frag_depth as an optimization.
  892. // It is not to workaround an issue with Edge:
  893. // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12120362/
  894. modifiedVS +=
  895. 'varying float v_WindowZ;\n' +
  896. 'void main() {\n' +
  897. ' czm_non_depth_clamp_main();\n' +
  898. ' vec4 position = gl_Position;\n' +
  899. ' v_WindowZ = (0.5 * (position.z / position.w) + 0.5) * position.w;\n' +
  900. ' position.z = min(position.z, position.w);\n' +
  901. ' gl_Position = position;\n' +
  902. '}\n';
  903. return modifiedVS;
  904. }
  905. function depthClampFS(fragmentShaderSource) {
  906. var modifiedFS = ShaderSource.replaceMain(fragmentShaderSource, 'czm_non_depth_clamp_main');
  907. modifiedFS +=
  908. 'varying float v_WindowZ;\n' +
  909. 'void main() {\n' +
  910. ' czm_non_depth_clamp_main();\n' +
  911. '#if defined(GL_EXT_frag_depth) && !defined(LOG_DEPTH)\n' +
  912. ' gl_FragDepthEXT = min(v_WindowZ * gl_FragCoord.w, 1.0);\n' +
  913. '#endif\n' +
  914. '}\n';
  915. modifiedFS =
  916. '#ifdef GL_EXT_frag_depth\n' +
  917. '#extension GL_EXT_frag_depth : enable\n' +
  918. '#endif\n' +
  919. modifiedFS;
  920. return modifiedFS;
  921. }
  922. function validateShaderMatching(shaderProgram, attributeLocations) {
  923. // For a VAO and shader program to be compatible, the VAO must have
  924. // all active attribute in the shader program. The VAO may have
  925. // extra attributes with the only concern being a potential
  926. // performance hit due to extra memory bandwidth and cache pollution.
  927. // The shader source could have extra attributes that are not used,
  928. // but there is no guarantee they will be optimized out.
  929. //
  930. // Here, we validate that the VAO has all attributes required
  931. // to match the shader program.
  932. var shaderAttributes = shaderProgram.vertexAttributes;
  933. //>>includeStart('debug', pragmas.debug);
  934. for (var name in shaderAttributes) {
  935. if (shaderAttributes.hasOwnProperty(name)) {
  936. if (!defined(attributeLocations[name])) {
  937. throw new DeveloperError('Appearance/Geometry mismatch. The appearance requires vertex shader attribute input \'' + name +
  938. '\', which was not computed as part of the Geometry. Use the appearance\'s vertexFormat property when constructing the geometry.');
  939. }
  940. }
  941. }
  942. //>>includeEnd('debug');
  943. }
  944. function getUniformFunction(uniforms, name) {
  945. return function() {
  946. return uniforms[name];
  947. };
  948. }
  949. var numberOfCreationWorkers = Math.max(FeatureDetection.hardwareConcurrency - 1, 1);
  950. var createGeometryTaskProcessors;
  951. var combineGeometryTaskProcessor = new TaskProcessor('combineGeometry', Number.POSITIVE_INFINITY);
  952. function loadAsynchronous(primitive, frameState) {
  953. var instances;
  954. var geometry;
  955. var i;
  956. var j;
  957. var instanceIds = primitive._instanceIds;
  958. if (primitive._state === PrimitiveState.READY) {
  959. instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  960. var length = primitive._numberOfInstances = instances.length;
  961. var promises = [];
  962. var subTasks = [];
  963. for (i = 0; i < length; ++i) {
  964. geometry = instances[i].geometry;
  965. instanceIds.push(instances[i].id);
  966. //>>includeStart('debug', pragmas.debug);
  967. if (!defined(geometry._workerName)) {
  968. throw new DeveloperError('_workerName must be defined for asynchronous geometry.');
  969. }
  970. //>>includeEnd('debug');
  971. subTasks.push({
  972. moduleName : geometry._workerName,
  973. geometry : geometry
  974. });
  975. }
  976. if (!defined(createGeometryTaskProcessors)) {
  977. createGeometryTaskProcessors = new Array(numberOfCreationWorkers);
  978. for (i = 0; i < numberOfCreationWorkers; i++) {
  979. createGeometryTaskProcessors[i] = new TaskProcessor('createGeometry', Number.POSITIVE_INFINITY);
  980. }
  981. }
  982. var subTask;
  983. subTasks = subdivideArray(subTasks, numberOfCreationWorkers);
  984. for (i = 0; i < subTasks.length; i++) {
  985. var packedLength = 0;
  986. var workerSubTasks = subTasks[i];
  987. var workerSubTasksLength = workerSubTasks.length;
  988. for (j = 0; j < workerSubTasksLength; ++j) {
  989. subTask = workerSubTasks[j];
  990. geometry = subTask.geometry;
  991. if (defined(geometry.constructor.pack)) {
  992. subTask.offset = packedLength;
  993. packedLength += defaultValue(geometry.constructor.packedLength, geometry.packedLength);
  994. }
  995. }
  996. var subTaskTransferableObjects;
  997. if (packedLength > 0) {
  998. var array = new Float64Array(packedLength);
  999. subTaskTransferableObjects = [array.buffer];
  1000. for (j = 0; j < workerSubTasksLength; ++j) {
  1001. subTask = workerSubTasks[j];
  1002. geometry = subTask.geometry;
  1003. if (defined(geometry.constructor.pack)) {
  1004. geometry.constructor.pack(geometry, array, subTask.offset);
  1005. subTask.geometry = array;
  1006. }
  1007. }
  1008. }
  1009. promises.push(createGeometryTaskProcessors[i].scheduleTask({
  1010. subTasks : subTasks[i]
  1011. }, subTaskTransferableObjects));
  1012. }
  1013. primitive._state = PrimitiveState.CREATING;
  1014. when.all(promises, function(results) {
  1015. primitive._createGeometryResults = results;
  1016. primitive._state = PrimitiveState.CREATED;
  1017. }).otherwise(function(error) {
  1018. setReady(primitive, frameState, PrimitiveState.FAILED, error);
  1019. });
  1020. } else if (primitive._state === PrimitiveState.CREATED) {
  1021. var transferableObjects = [];
  1022. instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  1023. var scene3DOnly = frameState.scene3DOnly;
  1024. var projection = frameState.mapProjection;
  1025. var promise = combineGeometryTaskProcessor.scheduleTask(PrimitivePipeline.packCombineGeometryParameters({
  1026. createGeometryResults : primitive._createGeometryResults,
  1027. instances : instances,
  1028. ellipsoid : projection.ellipsoid,
  1029. projection : projection,
  1030. elementIndexUintSupported : frameState.context.elementIndexUint,
  1031. scene3DOnly : scene3DOnly,
  1032. vertexCacheOptimize : primitive.vertexCacheOptimize,
  1033. compressVertices : primitive.compressVertices,
  1034. modelMatrix : primitive.modelMatrix,
  1035. createPickOffsets : primitive._createPickOffsets
  1036. }, transferableObjects), transferableObjects);
  1037. primitive._createGeometryResults = undefined;
  1038. primitive._state = PrimitiveState.COMBINING;
  1039. when(promise, function(packedResult) {
  1040. var result = PrimitivePipeline.unpackCombineGeometryResults(packedResult);
  1041. primitive._geometries = result.geometries;
  1042. primitive._attributeLocations = result.attributeLocations;
  1043. primitive.modelMatrix = Matrix4.clone(result.modelMatrix, primitive.modelMatrix);
  1044. primitive._pickOffsets = result.pickOffsets;
  1045. primitive._offsetInstanceExtend = result.offsetInstanceExtend;
  1046. primitive._instanceBoundingSpheres = result.boundingSpheres;
  1047. primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
  1048. if (defined(primitive._geometries) && primitive._geometries.length > 0) {
  1049. primitive._recomputeBoundingSpheres = true;
  1050. primitive._state = PrimitiveState.COMBINED;
  1051. } else {
  1052. setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
  1053. }
  1054. }).otherwise(function(error) {
  1055. setReady(primitive, frameState, PrimitiveState.FAILED, error);
  1056. });
  1057. }
  1058. }
  1059. function loadSynchronous(primitive, frameState) {
  1060. var instances = (isArray(primitive.geometryInstances)) ? primitive.geometryInstances : [primitive.geometryInstances];
  1061. var length = primitive._numberOfInstances = instances.length;
  1062. var clonedInstances = new Array(length);
  1063. var instanceIds = primitive._instanceIds;
  1064. var instance;
  1065. var i;
  1066. var geometryIndex = 0;
  1067. for (i = 0; i < length; i++) {
  1068. instance = instances[i];
  1069. var geometry = instance.geometry;
  1070. var createdGeometry;
  1071. if (defined(geometry.attributes) && defined(geometry.primitiveType)) {
  1072. createdGeometry = cloneGeometry(geometry);
  1073. } else {
  1074. createdGeometry = geometry.constructor.createGeometry(geometry);
  1075. }
  1076. clonedInstances[geometryIndex++] = cloneInstance(instance, createdGeometry);
  1077. instanceIds.push(instance.id);
  1078. }
  1079. clonedInstances.length = geometryIndex;
  1080. var scene3DOnly = frameState.scene3DOnly;
  1081. var projection = frameState.mapProjection;
  1082. var result = PrimitivePipeline.combineGeometry({
  1083. instances : clonedInstances,
  1084. ellipsoid : projection.ellipsoid,
  1085. projection : projection,
  1086. elementIndexUintSupported : frameState.context.elementIndexUint,
  1087. scene3DOnly : scene3DOnly,
  1088. vertexCacheOptimize : primitive.vertexCacheOptimize,
  1089. compressVertices : primitive.compressVertices,
  1090. modelMatrix : primitive.modelMatrix,
  1091. createPickOffsets : primitive._createPickOffsets
  1092. });
  1093. primitive._geometries = result.geometries;
  1094. primitive._attributeLocations = result.attributeLocations;
  1095. primitive.modelMatrix = Matrix4.clone(result.modelMatrix, primitive.modelMatrix);
  1096. primitive._pickOffsets = result.pickOffsets;
  1097. primitive._offsetInstanceExtend = result.offsetInstanceExtend;
  1098. primitive._instanceBoundingSpheres = result.boundingSpheres;
  1099. primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
  1100. if (defined(primitive._geometries) && primitive._geometries.length > 0) {
  1101. primitive._recomputeBoundingSpheres = true;
  1102. primitive._state = PrimitiveState.COMBINED;
  1103. } else {
  1104. setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
  1105. }
  1106. }
  1107. function recomputeBoundingSpheres(primitive, frameState) {
  1108. var offsetIndex = primitive._batchTableAttributeIndices.offset;
  1109. if (!primitive._recomputeBoundingSpheres || !defined(offsetIndex)) {
  1110. primitive._recomputeBoundingSpheres = false;
  1111. return;
  1112. }
  1113. var i;
  1114. var offsetInstanceExtend = primitive._offsetInstanceExtend;
  1115. var boundingSpheres = primitive._instanceBoundingSpheres;
  1116. var length = boundingSpheres.length;
  1117. var newBoundingSpheres = primitive._tempBoundingSpheres;
  1118. if (!defined(newBoundingSpheres)) {
  1119. newBoundingSpheres = new Array(length);
  1120. for (i = 0; i < length; i++) {
  1121. newBoundingSpheres[i] = new BoundingSphere();
  1122. }
  1123. primitive._tempBoundingSpheres = newBoundingSpheres;
  1124. }
  1125. for (i = 0; i < length; ++i) {
  1126. var newBS = newBoundingSpheres[i];
  1127. var offset = primitive._batchTable.getBatchedAttribute(i, offsetIndex, new Cartesian3());
  1128. newBS = boundingSpheres[i].clone(newBS);
  1129. transformBoundingSphere(newBS, offset, offsetInstanceExtend[i]);
  1130. }
  1131. var combinedBS = [];
  1132. var combinedWestBS = [];
  1133. var combinedEastBS = [];
  1134. for (i = 0; i < length; ++i) {
  1135. var bs = newBoundingSpheres[i];
  1136. var minX = bs.center.x - bs.radius;
  1137. if (minX > 0 || BoundingSphere.intersectPlane(bs, Plane.ORIGIN_ZX_PLANE) !== Intersect.INTERSECTING) {
  1138. combinedBS.push(bs);
  1139. } else {
  1140. combinedWestBS.push(bs);
  1141. combinedEastBS.push(bs);
  1142. }
  1143. }
  1144. var resultBS1 = combinedBS[0];
  1145. var resultBS2 = combinedEastBS[0];
  1146. var resultBS3 = combinedWestBS[0];
  1147. for (i = 1; i < combinedBS.length; i++) {
  1148. resultBS1 = BoundingSphere.union(resultBS1, combinedBS[i]);
  1149. }
  1150. for (i = 1; i < combinedEastBS.length; i++) {
  1151. resultBS2 = BoundingSphere.union(resultBS2, combinedEastBS[i]);
  1152. }
  1153. for (i = 1; i < combinedWestBS.length; i++) {
  1154. resultBS3 = BoundingSphere.union(resultBS3, combinedWestBS[i]);
  1155. }
  1156. var result = [];
  1157. if (defined(resultBS1)) {
  1158. result.push(resultBS1);
  1159. }
  1160. if (defined(resultBS2)) {
  1161. result.push(resultBS2);
  1162. }
  1163. if (defined(resultBS3)) {
  1164. result.push(resultBS3);
  1165. }
  1166. for (i = 0; i < result.length; i++) {
  1167. var boundingSphere = result[i].clone(primitive._boundingSpheres[i]);
  1168. primitive._boundingSpheres[i] = boundingSphere;
  1169. primitive._boundingSphereCV[i] = BoundingSphere.projectTo2D(boundingSphere, frameState.mapProjection, primitive._boundingSphereCV[i]);
  1170. }
  1171. Primitive._updateBoundingVolumes(primitive, frameState, primitive.modelMatrix, true);
  1172. primitive._recomputeBoundingSpheres = false;
  1173. }
  1174. var scratchBoundingSphereCenterEncoded = new EncodedCartesian3();
  1175. var scratchBoundingSphereCartographic = new Cartographic();
  1176. var scratchBoundingSphereCenter2D = new Cartesian3();
  1177. var scratchBoundingSphere = new BoundingSphere();
  1178. function updateBatchTableBoundingSpheres(primitive, frameState) {
  1179. var hasDistanceDisplayCondition = defined(primitive._batchTableAttributeIndices.distanceDisplayCondition);
  1180. if (!hasDistanceDisplayCondition || primitive._batchTableBoundingSpheresUpdated) {
  1181. return;
  1182. }
  1183. var indices = primitive._batchTableBoundingSphereAttributeIndices;
  1184. var center3DHighIndex = indices.center3DHigh;
  1185. var center3DLowIndex = indices.center3DLow;
  1186. var center2DHighIndex = indices.center2DHigh;
  1187. var center2DLowIndex = indices.center2DLow;
  1188. var radiusIndex = indices.radius;
  1189. var projection = frameState.mapProjection;
  1190. var ellipsoid = projection.ellipsoid;
  1191. var batchTable = primitive._batchTable;
  1192. var boundingSpheres = primitive._instanceBoundingSpheres;
  1193. var length = boundingSpheres.length;
  1194. for (var i = 0; i < length; ++i) {
  1195. var boundingSphere = boundingSpheres[i];
  1196. if (!defined(boundingSphere)) {
  1197. continue;
  1198. }
  1199. var modelMatrix = primitive.modelMatrix;
  1200. if (defined(modelMatrix)) {
  1201. boundingSphere = BoundingSphere.transform(boundingSphere, modelMatrix, scratchBoundingSphere);
  1202. }
  1203. var center = boundingSphere.center;
  1204. var radius = boundingSphere.radius;
  1205. var encodedCenter = EncodedCartesian3.fromCartesian(center, scratchBoundingSphereCenterEncoded);
  1206. batchTable.setBatchedAttribute(i, center3DHighIndex, encodedCenter.high);
  1207. batchTable.setBatchedAttribute(i, center3DLowIndex, encodedCenter.low);
  1208. if (!frameState.scene3DOnly) {
  1209. var cartographic = ellipsoid.cartesianToCartographic(center, scratchBoundingSphereCartographic);
  1210. var center2D = projection.project(cartographic, scratchBoundingSphereCenter2D);
  1211. encodedCenter = EncodedCartesian3.fromCartesian(center2D, scratchBoundingSphereCenterEncoded);
  1212. batchTable.setBatchedAttribute(i, center2DHighIndex, encodedCenter.high);
  1213. batchTable.setBatchedAttribute(i, center2DLowIndex, encodedCenter.low);
  1214. }
  1215. batchTable.setBatchedAttribute(i, radiusIndex, radius);
  1216. }
  1217. primitive._batchTableBoundingSpheresUpdated = true;
  1218. }
  1219. var offsetScratchCartesian = new Cartesian3();
  1220. var offsetCenterScratch = new Cartesian3();
  1221. function updateBatchTableOffsets(primitive, frameState) {
  1222. var hasOffset = defined(primitive._batchTableAttributeIndices.offset);
  1223. if (!hasOffset || primitive._batchTableOffsetsUpdated || frameState.scene3DOnly) {
  1224. return;
  1225. }
  1226. var index2D = primitive._batchTableOffsetAttribute2DIndex;
  1227. var projection = frameState.mapProjection;
  1228. var ellipsoid = projection.ellipsoid;
  1229. var batchTable = primitive._batchTable;
  1230. var boundingSpheres = primitive._instanceBoundingSpheres;
  1231. var length = boundingSpheres.length;
  1232. for (var i = 0; i < length; ++i) {
  1233. var boundingSphere = boundingSpheres[i];
  1234. if (!defined(boundingSphere)) {
  1235. continue;
  1236. }
  1237. var offset = batchTable.getBatchedAttribute(i, primitive._batchTableAttributeIndices.offset);
  1238. if (Cartesian3.equals(offset, Cartesian3.ZERO)) {
  1239. batchTable.setBatchedAttribute(i, index2D, Cartesian3.ZERO);
  1240. continue;
  1241. }
  1242. var modelMatrix = primitive.modelMatrix;
  1243. if (defined(modelMatrix)) {
  1244. boundingSphere = BoundingSphere.transform(boundingSphere, modelMatrix, scratchBoundingSphere);
  1245. }
  1246. var center = boundingSphere.center;
  1247. center = ellipsoid.scaleToGeodeticSurface(center, offsetCenterScratch);
  1248. var cartographic = ellipsoid.cartesianToCartographic(center, scratchBoundingSphereCartographic);
  1249. var center2D = projection.project(cartographic, scratchBoundingSphereCenter2D);
  1250. var newPoint = Cartesian3.add(offset, center, offsetScratchCartesian);
  1251. cartographic = ellipsoid.cartesianToCartographic(newPoint, cartographic);
  1252. var newPointProjected = projection.project(cartographic, offsetScratchCartesian);
  1253. var newVector = Cartesian3.subtract(newPointProjected, center2D, offsetScratchCartesian);
  1254. var x = newVector.x;
  1255. newVector.x = newVector.z;
  1256. newVector.z = newVector.y;
  1257. newVector.y = x;
  1258. batchTable.setBatchedAttribute(i, index2D, newVector);
  1259. }
  1260. primitive._batchTableOffsetsUpdated = true;
  1261. }
  1262. function createVertexArray(primitive, frameState) {
  1263. var attributeLocations = primitive._attributeLocations;
  1264. var geometries = primitive._geometries;
  1265. var scene3DOnly = frameState.scene3DOnly;
  1266. var context = frameState.context;
  1267. var va = [];
  1268. var length = geometries.length;
  1269. for (var i = 0; i < length; ++i) {
  1270. var geometry = geometries[i];
  1271. va.push(VertexArray.fromGeometry({
  1272. context : context,
  1273. geometry : geometry,
  1274. attributeLocations : attributeLocations,
  1275. bufferUsage : BufferUsage.STATIC_DRAW,
  1276. interleave : primitive._interleave
  1277. }));
  1278. if (defined(primitive._createBoundingVolumeFunction)) {
  1279. primitive._createBoundingVolumeFunction(frameState, geometry);
  1280. } else {
  1281. primitive._boundingSpheres.push(BoundingSphere.clone(geometry.boundingSphere));
  1282. primitive._boundingSphereWC.push(new BoundingSphere());
  1283. if (!scene3DOnly) {
  1284. var center = geometry.boundingSphereCV.center;
  1285. var x = center.x;
  1286. var y = center.y;
  1287. var z = center.z;
  1288. center.x = z;
  1289. center.y = x;
  1290. center.z = y;
  1291. primitive._boundingSphereCV.push(BoundingSphere.clone(geometry.boundingSphereCV));
  1292. primitive._boundingSphere2D.push(new BoundingSphere());
  1293. primitive._boundingSphereMorph.push(new BoundingSphere());
  1294. }
  1295. }
  1296. }
  1297. primitive._va = va;
  1298. primitive._primitiveType = geometries[0].primitiveType;
  1299. if (primitive.releaseGeometryInstances) {
  1300. primitive.geometryInstances = undefined;
  1301. }
  1302. primitive._geometries = undefined;
  1303. setReady(primitive, frameState, PrimitiveState.COMPLETE, undefined);
  1304. }
  1305. function createRenderStates(primitive, context, appearance, twoPasses) {
  1306. var renderState = appearance.getRenderState();
  1307. var rs;
  1308. if (twoPasses) {
  1309. rs = clone(renderState, false);
  1310. rs.cull = {
  1311. enabled : true,
  1312. face : CullFace.BACK
  1313. };
  1314. primitive._frontFaceRS = RenderState.fromCache(rs);
  1315. rs.cull.face = CullFace.FRONT;
  1316. primitive._backFaceRS = RenderState.fromCache(rs);
  1317. } else {
  1318. primitive._frontFaceRS = RenderState.fromCache(renderState);
  1319. primitive._backFaceRS = primitive._frontFaceRS;
  1320. }
  1321. rs = clone(renderState, false);
  1322. if (defined(primitive._depthFailAppearance)) {
  1323. rs.depthTest.enabled = false;
  1324. }
  1325. if (defined(primitive._depthFailAppearance)) {
  1326. renderState = primitive._depthFailAppearance.getRenderState();
  1327. rs = clone(renderState, false);
  1328. rs.depthTest.func = DepthFunction.GREATER;
  1329. if (twoPasses) {
  1330. rs.cull = {
  1331. enabled : true,
  1332. face : CullFace.BACK
  1333. };
  1334. primitive._frontFaceDepthFailRS = RenderState.fromCache(rs);
  1335. rs.cull.face = CullFace.FRONT;
  1336. primitive._backFaceDepthFailRS = RenderState.fromCache(rs);
  1337. } else {
  1338. primitive._frontFaceDepthFailRS = RenderState.fromCache(rs);
  1339. primitive._backFaceDepthFailRS = primitive._frontFaceRS;
  1340. }
  1341. }
  1342. }
  1343. function createShaderProgram(primitive, frameState, appearance) {
  1344. var context = frameState.context;
  1345. var attributeLocations = primitive._attributeLocations;
  1346. var vs = primitive._batchTable.getVertexShaderCallback()(appearance.vertexShaderSource);
  1347. vs = Primitive._appendOffsetToShader(primitive, vs);
  1348. vs = Primitive._appendShowToShader(primitive, vs);
  1349. vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs, frameState.scene3DOnly);
  1350. vs = appendPickToVertexShader(vs);
  1351. vs = Primitive._updateColorAttribute(primitive, vs, false);
  1352. vs = modifyForEncodedNormals(primitive, vs);
  1353. vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
  1354. var fs = appearance.getFragmentShaderSource();
  1355. fs = appendPickToFragmentShader(fs);
  1356. primitive._sp = ShaderProgram.replaceCache({
  1357. context : context,
  1358. shaderProgram : primitive._sp,
  1359. vertexShaderSource : vs,
  1360. fragmentShaderSource : fs,
  1361. attributeLocations : attributeLocations
  1362. });
  1363. validateShaderMatching(primitive._sp, attributeLocations);
  1364. if (defined(primitive._depthFailAppearance)) {
  1365. vs = primitive._batchTable.getVertexShaderCallback()(primitive._depthFailAppearance.vertexShaderSource);
  1366. vs = Primitive._appendShowToShader(primitive, vs);
  1367. vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs, frameState.scene3DOnly);
  1368. vs = appendPickToVertexShader(vs);
  1369. vs = Primitive._updateColorAttribute(primitive, vs, true);
  1370. vs = modifyForEncodedNormals(primitive, vs);
  1371. vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
  1372. vs = depthClampVS(vs);
  1373. fs = primitive._depthFailAppearance.getFragmentShaderSource();
  1374. fs = appendPickToFragmentShader(fs);
  1375. fs = depthClampFS(fs);
  1376. primitive._spDepthFail = ShaderProgram.replaceCache({
  1377. context : context,
  1378. shaderProgram : primitive._spDepthFail,
  1379. vertexShaderSource : vs,
  1380. fragmentShaderSource : fs,
  1381. attributeLocations : attributeLocations
  1382. });
  1383. validateShaderMatching(primitive._spDepthFail, attributeLocations);
  1384. }
  1385. }
  1386. var modifiedModelViewScratch = new Matrix4();
  1387. var rtcScratch = new Cartesian3();
  1388. function getUniforms(primitive, appearance, material, frameState) {
  1389. // Create uniform map by combining uniforms from the appearance and material if either have uniforms.
  1390. var materialUniformMap = defined(material) ? material._uniforms : undefined;
  1391. var appearanceUniformMap = {};
  1392. var appearanceUniforms = appearance.uniforms;
  1393. if (defined(appearanceUniforms)) {
  1394. // Convert to uniform map of functions for the renderer
  1395. for (var name in appearanceUniforms) {
  1396. if (appearanceUniforms.hasOwnProperty(name)) {
  1397. //>>includeStart('debug', pragmas.debug);
  1398. if (defined(materialUniformMap) && defined(materialUniformMap[name])) {
  1399. // Later, we could rename uniforms behind-the-scenes if needed.
  1400. throw new DeveloperError('Appearance and material have a uniform with the same name: ' + name);
  1401. }
  1402. //>>includeEnd('debug');
  1403. appearanceUniformMap[name] = getUniformFunction(appearanceUniforms, name);
  1404. }
  1405. }
  1406. }
  1407. var uniforms = combine(appearanceUniformMap, materialUniformMap);
  1408. uniforms = primitive._batchTable.getUniformMapCallback()(uniforms);
  1409. if (defined(primitive.rtcCenter)) {
  1410. uniforms.u_modifiedModelView = function() {
  1411. var viewMatrix = frameState.context.uniformState.view;
  1412. Matrix4.multiply(viewMatrix, primitive._modelMatrix, modifiedModelViewScratch);
  1413. Matrix4.multiplyByPoint(modifiedModelViewScratch, primitive.rtcCenter, rtcScratch);
  1414. Matrix4.setTranslation(modifiedModelViewScratch, rtcScratch, modifiedModelViewScratch);
  1415. return modifiedModelViewScratch;
  1416. };
  1417. }
  1418. return uniforms;
  1419. }
  1420. function createCommands(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands, frameState) {
  1421. var uniforms = getUniforms(primitive, appearance, material, frameState);
  1422. var depthFailUniforms;
  1423. if (defined(primitive._depthFailAppearance)) {
  1424. depthFailUniforms = getUniforms(primitive, primitive._depthFailAppearance, primitive._depthFailAppearance.material, frameState);
  1425. }
  1426. var pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
  1427. var multiplier = twoPasses ? 2 : 1;
  1428. multiplier *= defined(primitive._depthFailAppearance) ? 2 : 1;
  1429. colorCommands.length = primitive._va.length * multiplier;
  1430. var length = colorCommands.length;
  1431. var vaIndex = 0;
  1432. for (var i = 0; i < length; ++i) {
  1433. var colorCommand;
  1434. if (twoPasses) {
  1435. colorCommand = colorCommands[i];
  1436. if (!defined(colorCommand)) {
  1437. colorCommand = colorCommands[i] = new DrawCommand({
  1438. owner : primitive,
  1439. primitiveType : primitive._primitiveType
  1440. });
  1441. }
  1442. colorCommand.vertexArray = primitive._va[vaIndex];
  1443. colorCommand.renderState = primitive._backFaceRS;
  1444. colorCommand.shaderProgram = primitive._sp;
  1445. colorCommand.uniformMap = uniforms;
  1446. colorCommand.pass = pass;
  1447. ++i;
  1448. }
  1449. colorCommand = colorCommands[i];
  1450. if (!defined(colorCommand)) {
  1451. colorCommand = colorCommands[i] = new DrawCommand({
  1452. owner : primitive,
  1453. primitiveType : primitive._primitiveType
  1454. });
  1455. }
  1456. colorCommand.vertexArray = primitive._va[vaIndex];
  1457. colorCommand.renderState = primitive._frontFaceRS;
  1458. colorCommand.shaderProgram = primitive._sp;
  1459. colorCommand.uniformMap = uniforms;
  1460. colorCommand.pass = pass;
  1461. if (defined(primitive._depthFailAppearance)) {
  1462. if (twoPasses) {
  1463. ++i;
  1464. colorCommand = colorCommands[i];
  1465. if (!defined(colorCommand)) {
  1466. colorCommand = colorCommands[i] = new DrawCommand({
  1467. owner : primitive,
  1468. primitiveType : primitive._primitiveType
  1469. });
  1470. }
  1471. colorCommand.vertexArray = primitive._va[vaIndex];
  1472. colorCommand.renderState = primitive._backFaceDepthFailRS;
  1473. colorCommand.shaderProgram = primitive._spDepthFail;
  1474. colorCommand.uniformMap = depthFailUniforms;
  1475. colorCommand.pass = pass;
  1476. }
  1477. ++i;
  1478. colorCommand = colorCommands[i];
  1479. if (!defined(colorCommand)) {
  1480. colorCommand = colorCommands[i] = new DrawCommand({
  1481. owner : primitive,
  1482. primitiveType : primitive._primitiveType
  1483. });
  1484. }
  1485. colorCommand.vertexArray = primitive._va[vaIndex];
  1486. colorCommand.renderState = primitive._frontFaceDepthFailRS;
  1487. colorCommand.shaderProgram = primitive._spDepthFail;
  1488. colorCommand.uniformMap = depthFailUniforms;
  1489. colorCommand.pass = pass;
  1490. }
  1491. ++vaIndex;
  1492. }
  1493. }
  1494. Primitive._updateBoundingVolumes = function(primitive, frameState, modelMatrix, forceUpdate) {
  1495. var i;
  1496. var length;
  1497. var boundingSphere;
  1498. if (forceUpdate || !Matrix4.equals(modelMatrix, primitive._modelMatrix)) {
  1499. Matrix4.clone(modelMatrix, primitive._modelMatrix);
  1500. length = primitive._boundingSpheres.length;
  1501. for (i = 0; i < length; ++i) {
  1502. boundingSphere = primitive._boundingSpheres[i];
  1503. if (defined(boundingSphere)) {
  1504. primitive._boundingSphereWC[i] = BoundingSphere.transform(boundingSphere, modelMatrix, primitive._boundingSphereWC[i]);
  1505. if (!frameState.scene3DOnly) {
  1506. primitive._boundingSphere2D[i] = BoundingSphere.clone(primitive._boundingSphereCV[i], primitive._boundingSphere2D[i]);
  1507. primitive._boundingSphere2D[i].center.x = 0.0;
  1508. primitive._boundingSphereMorph[i] = BoundingSphere.union(primitive._boundingSphereWC[i], primitive._boundingSphereCV[i]);
  1509. }
  1510. }
  1511. }
  1512. }
  1513. // Update bounding volumes for primitives that are sized in pixels.
  1514. // The pixel size in meters varies based on the distance from the camera.
  1515. var pixelSize = primitive.appearance.pixelSize;
  1516. if (defined(pixelSize)) {
  1517. length = primitive._boundingSpheres.length;
  1518. for (i = 0; i < length; ++i) {
  1519. boundingSphere = primitive._boundingSpheres[i];
  1520. var boundingSphereWC = primitive._boundingSphereWC[i];
  1521. var pixelSizeInMeters = frameState.camera.getPixelSize(boundingSphere, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight);
  1522. var sizeInMeters = pixelSizeInMeters * pixelSize;
  1523. boundingSphereWC.radius = boundingSphere.radius + sizeInMeters;
  1524. }
  1525. }
  1526. };
  1527. function updateAndQueueCommands(primitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume, twoPasses) {
  1528. //>>includeStart('debug', pragmas.debug);
  1529. if (frameState.mode !== SceneMode.SCENE3D && !Matrix4.equals(modelMatrix, Matrix4.IDENTITY)) {
  1530. throw new DeveloperError('Primitive.modelMatrix is only supported in 3D mode.');
  1531. }
  1532. //>>includeEnd('debug');
  1533. Primitive._updateBoundingVolumes(primitive, frameState, modelMatrix);
  1534. var boundingSpheres;
  1535. if (frameState.mode === SceneMode.SCENE3D) {
  1536. boundingSpheres = primitive._boundingSphereWC;
  1537. } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
  1538. boundingSpheres = primitive._boundingSphereCV;
  1539. } else if (frameState.mode === SceneMode.SCENE2D && defined(primitive._boundingSphere2D)) {
  1540. boundingSpheres = primitive._boundingSphere2D;
  1541. } else if (defined(primitive._boundingSphereMorph)) {
  1542. boundingSpheres = primitive._boundingSphereMorph;
  1543. }
  1544. var commandList = frameState.commandList;
  1545. var passes = frameState.passes;
  1546. if (passes.render || passes.pick) {
  1547. var allowPicking = primitive.allowPicking;
  1548. var castShadows = ShadowMode.castShadows(primitive.shadows);
  1549. var receiveShadows = ShadowMode.receiveShadows(primitive.shadows);
  1550. var colorLength = colorCommands.length;
  1551. var factor = twoPasses ? 2 : 1;
  1552. factor *= defined(primitive._depthFailAppearance) ? 2 : 1;
  1553. for (var j = 0; j < colorLength; ++j) {
  1554. var sphereIndex = Math.floor(j / factor);
  1555. var colorCommand = colorCommands[j];
  1556. colorCommand.modelMatrix = modelMatrix;
  1557. colorCommand.boundingVolume = boundingSpheres[sphereIndex];
  1558. colorCommand.cull = cull;
  1559. colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;
  1560. colorCommand.castShadows = castShadows;
  1561. colorCommand.receiveShadows = receiveShadows;
  1562. if (allowPicking) {
  1563. colorCommand.pickId = 'v_pickColor';
  1564. } else {
  1565. colorCommand.pickId = undefined;
  1566. }
  1567. commandList.push(colorCommand);
  1568. }
  1569. }
  1570. }
  1571. /**
  1572. * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
  1573. * get the draw commands needed to render this primitive.
  1574. * <p>
  1575. * Do not call this function directly. This is documented just to
  1576. * list the exceptions that may be propagated when the scene is rendered:
  1577. * </p>
  1578. *
  1579. * @exception {DeveloperError} All instance geometries must have the same primitiveType.
  1580. * @exception {DeveloperError} Appearance and material have a uniform with the same name.
  1581. * @exception {DeveloperError} Primitive.modelMatrix is only supported in 3D mode.
  1582. * @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
  1583. */
  1584. Primitive.prototype.update = function(frameState) {
  1585. if (((!defined(this.geometryInstances)) && (this._va.length === 0)) ||
  1586. (defined(this.geometryInstances) && isArray(this.geometryInstances) && this.geometryInstances.length === 0) ||
  1587. (!defined(this.appearance)) ||
  1588. (frameState.mode !== SceneMode.SCENE3D && frameState.scene3DOnly) ||
  1589. (!frameState.passes.render && !frameState.passes.pick)) {
  1590. return;
  1591. }
  1592. if (defined(this._error)) {
  1593. throw this._error;
  1594. }
  1595. //>>includeStart('debug', pragmas.debug);
  1596. if (defined(this.rtcCenter) && !frameState.scene3DOnly) {
  1597. throw new DeveloperError('RTC rendering is only available for 3D only scenes.');
  1598. }
  1599. //>>includeEnd('debug');
  1600. if (this._state === PrimitiveState.FAILED) {
  1601. return;
  1602. }
  1603. var context = frameState.context;
  1604. if (!defined(this._batchTable)) {
  1605. createBatchTable(this, context);
  1606. }
  1607. if (this._batchTable.attributes.length > 0) {
  1608. if (ContextLimits.maximumVertexTextureImageUnits === 0) {
  1609. throw new RuntimeError('Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.');
  1610. }
  1611. this._batchTable.update(frameState);
  1612. }
  1613. if (this._state !== PrimitiveState.COMPLETE && this._state !== PrimitiveState.COMBINED) {
  1614. if (this.asynchronous) {
  1615. loadAsynchronous(this, frameState);
  1616. } else {
  1617. loadSynchronous(this, frameState);
  1618. }
  1619. }
  1620. if (this._state === PrimitiveState.COMBINED) {
  1621. updateBatchTableBoundingSpheres(this, frameState);
  1622. updateBatchTableOffsets(this, frameState);
  1623. createVertexArray(this, frameState);
  1624. }
  1625. if (!this.show || this._state !== PrimitiveState.COMPLETE) {
  1626. return;
  1627. }
  1628. if (!this._batchTableOffsetsUpdated) {
  1629. updateBatchTableOffsets(this, frameState);
  1630. }
  1631. if (this._recomputeBoundingSpheres) {
  1632. recomputeBoundingSpheres(this, frameState);
  1633. }
  1634. // Create or recreate render state and shader program if appearance/material changed
  1635. var appearance = this.appearance;
  1636. var material = appearance.material;
  1637. var createRS = false;
  1638. var createSP = false;
  1639. if (this._appearance !== appearance) {
  1640. this._appearance = appearance;
  1641. this._material = material;
  1642. createRS = true;
  1643. createSP = true;
  1644. } else if (this._material !== material) {
  1645. this._material = material;
  1646. createSP = true;
  1647. }
  1648. var depthFailAppearance = this.depthFailAppearance;
  1649. var depthFailMaterial = defined(depthFailAppearance) ? depthFailAppearance.material : undefined;
  1650. if (this._depthFailAppearance !== depthFailAppearance) {
  1651. this._depthFailAppearance = depthFailAppearance;
  1652. this._depthFailMaterial = depthFailMaterial;
  1653. createRS = true;
  1654. createSP = true;
  1655. } else if (this._depthFailMaterial !== depthFailMaterial) {
  1656. this._depthFailMaterial = depthFailMaterial;
  1657. createSP = true;
  1658. }
  1659. var translucent = this._appearance.isTranslucent();
  1660. if (this._translucent !== translucent) {
  1661. this._translucent = translucent;
  1662. createRS = true;
  1663. }
  1664. if (defined(this._material)) {
  1665. this._material.update(context);
  1666. }
  1667. var twoPasses = appearance.closed && translucent;
  1668. if (createRS) {
  1669. var rsFunc = defaultValue(this._createRenderStatesFunction, createRenderStates);
  1670. rsFunc(this, context, appearance, twoPasses);
  1671. }
  1672. if (createSP) {
  1673. var spFunc = defaultValue(this._createShaderProgramFunction, createShaderProgram);
  1674. spFunc(this, frameState, appearance);
  1675. }
  1676. if (createRS || createSP) {
  1677. var commandFunc = defaultValue(this._createCommandsFunction, createCommands);
  1678. commandFunc(this, appearance, material, translucent, twoPasses, this._colorCommands, this._pickCommands, frameState);
  1679. }
  1680. var updateAndQueueCommandsFunc = defaultValue(this._updateAndQueueCommandsFunction, updateAndQueueCommands);
  1681. updateAndQueueCommandsFunc(this, frameState, this._colorCommands, this._pickCommands, this.modelMatrix, this.cull, this.debugShowBoundingVolume, twoPasses);
  1682. };
  1683. var offsetBoundingSphereScratch1 = new BoundingSphere();
  1684. var offsetBoundingSphereScratch2 = new BoundingSphere();
  1685. function transformBoundingSphere(boundingSphere, offset, offsetAttribute) {
  1686. if (offsetAttribute === GeometryOffsetAttribute.TOP) {
  1687. var origBS = BoundingSphere.clone(boundingSphere, offsetBoundingSphereScratch1);
  1688. var offsetBS = BoundingSphere.clone(boundingSphere, offsetBoundingSphereScratch2);
  1689. offsetBS.center = Cartesian3.add(offsetBS.center, offset, offsetBS.center);
  1690. boundingSphere = BoundingSphere.union(origBS, offsetBS, boundingSphere);
  1691. } else if (offsetAttribute === GeometryOffsetAttribute.ALL) {
  1692. boundingSphere.center = Cartesian3.add(boundingSphere.center, offset, boundingSphere.center);
  1693. }
  1694. return boundingSphere;
  1695. }
  1696. function createGetFunction(batchTable, instanceIndex, attributeIndex) {
  1697. return function() {
  1698. var attributeValue = batchTable.getBatchedAttribute(instanceIndex, attributeIndex);
  1699. var attribute = batchTable.attributes[attributeIndex];
  1700. var componentsPerAttribute = attribute.componentsPerAttribute;
  1701. var value = ComponentDatatype.createTypedArray(attribute.componentDatatype, componentsPerAttribute);
  1702. if (defined(attributeValue.constructor.pack)) {
  1703. attributeValue.constructor.pack(attributeValue, value, 0);
  1704. } else {
  1705. value[0] = attributeValue;
  1706. }
  1707. return value;
  1708. };
  1709. }
  1710. function createSetFunction(batchTable, instanceIndex, attributeIndex, primitive, name) {
  1711. return function(value) {
  1712. //>>includeStart('debug', pragmas.debug);
  1713. if (!defined(value) || !defined(value.length) || value.length < 1 || value.length > 4) {
  1714. throw new DeveloperError('value must be and array with length between 1 and 4.');
  1715. }
  1716. //>>includeEnd('debug');
  1717. var attributeValue = getAttributeValue(value);
  1718. batchTable.setBatchedAttribute(instanceIndex, attributeIndex, attributeValue);
  1719. if (name === 'offset') {
  1720. primitive._recomputeBoundingSpheres = true;
  1721. primitive._batchTableOffsetsUpdated = false;
  1722. }
  1723. };
  1724. }
  1725. var offsetScratch = new Cartesian3();
  1726. function createBoundingSphereProperties(primitive, properties, index) {
  1727. properties.boundingSphere = {
  1728. get : function() {
  1729. var boundingSphere = primitive._instanceBoundingSpheres[index];
  1730. if (defined(boundingSphere)) {
  1731. boundingSphere = boundingSphere.clone();
  1732. var modelMatrix = primitive.modelMatrix;
  1733. var offset = properties.offset;
  1734. if (defined(offset)) {
  1735. transformBoundingSphere(boundingSphere, Cartesian3.fromArray(offset.get(), 0, offsetScratch), primitive._offsetInstanceExtend[index]);
  1736. }
  1737. if (defined(modelMatrix)) {
  1738. boundingSphere = BoundingSphere.transform(boundingSphere, modelMatrix);
  1739. }
  1740. }
  1741. return boundingSphere;
  1742. }
  1743. };
  1744. properties.boundingSphereCV = {
  1745. get : function() {
  1746. return primitive._instanceBoundingSpheresCV[index];
  1747. }
  1748. };
  1749. }
  1750. function createPickIdProperty(primitive, properties, index) {
  1751. properties.pickId = {
  1752. get : function() {
  1753. return primitive._pickIds[index];
  1754. }
  1755. };
  1756. }
  1757. /**
  1758. * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
  1759. *
  1760. * @param {*} id The id of the {@link GeometryInstance}.
  1761. * @returns {Object} The typed array in the attribute's format or undefined if the is no instance with id.
  1762. *
  1763. * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
  1764. *
  1765. * @example
  1766. * var attributes = primitive.getGeometryInstanceAttributes('an id');
  1767. * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
  1768. * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  1769. * attributes.distanceDisplayCondition = Cesium.DistanceDisplayConditionGeometryInstanceAttribute.toValue(100.0, 10000.0);
  1770. * attributes.offset = Cesium.OffsetGeometryInstanceAttribute.toValue(Cartesian3.IDENTITY);
  1771. */
  1772. Primitive.prototype.getGeometryInstanceAttributes = function(id) {
  1773. //>>includeStart('debug', pragmas.debug);
  1774. if (!defined(id)) {
  1775. throw new DeveloperError('id is required');
  1776. }
  1777. if (!defined(this._batchTable)) {
  1778. throw new DeveloperError('must call update before calling getGeometryInstanceAttributes');
  1779. }
  1780. //>>includeEnd('debug');
  1781. var index = -1;
  1782. var lastIndex = this._lastPerInstanceAttributeIndex;
  1783. var ids = this._instanceIds;
  1784. var length = ids.length;
  1785. for (var i = 0; i < length; ++i) {
  1786. var curIndex = (lastIndex + i) % length;
  1787. if (id === ids[curIndex]) {
  1788. index = curIndex;
  1789. break;
  1790. }
  1791. }
  1792. if (index === -1) {
  1793. return undefined;
  1794. }
  1795. var attributes = this._perInstanceAttributeCache[index];
  1796. if (defined(attributes)) {
  1797. return attributes;
  1798. }
  1799. var batchTable = this._batchTable;
  1800. var perInstanceAttributeIndices = this._batchTableAttributeIndices;
  1801. attributes = {};
  1802. var properties = {};
  1803. for (var name in perInstanceAttributeIndices) {
  1804. if (perInstanceAttributeIndices.hasOwnProperty(name)) {
  1805. var attributeIndex = perInstanceAttributeIndices[name];
  1806. properties[name] = {
  1807. get : createGetFunction(batchTable, index, attributeIndex)
  1808. };
  1809. var createSetter = true;
  1810. var readOnlyAttributes = this._readOnlyInstanceAttributes;
  1811. if (createSetter && defined(readOnlyAttributes)) {
  1812. length = readOnlyAttributes.length;
  1813. for (var k = 0; k < length; ++k) {
  1814. if (name === readOnlyAttributes[k]) {
  1815. createSetter = false;
  1816. break;
  1817. }
  1818. }
  1819. }
  1820. if (createSetter) {
  1821. properties[name].set = createSetFunction(batchTable, index, attributeIndex, this, name);
  1822. }
  1823. }
  1824. }
  1825. createBoundingSphereProperties(this, properties, index);
  1826. createPickIdProperty(this, properties, index);
  1827. defineProperties(attributes, properties);
  1828. this._lastPerInstanceAttributeIndex = index;
  1829. this._perInstanceAttributeCache[index] = attributes;
  1830. return attributes;
  1831. };
  1832. /**
  1833. * Returns true if this object was destroyed; otherwise, false.
  1834. * <p>
  1835. * If this object was destroyed, it should not be used; calling any function other than
  1836. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  1837. * </p>
  1838. *
  1839. * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
  1840. *
  1841. * @see Primitive#destroy
  1842. */
  1843. Primitive.prototype.isDestroyed = function() {
  1844. return false;
  1845. };
  1846. /**
  1847. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  1848. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  1849. * <p>
  1850. * Once an object is destroyed, it should not be used; calling any function other than
  1851. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  1852. * assign the return value (<code>undefined</code>) to the object as done in the example.
  1853. * </p>
  1854. *
  1855. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  1856. *
  1857. *
  1858. * @example
  1859. * e = e && e.destroy();
  1860. *
  1861. * @see Primitive#isDestroyed
  1862. */
  1863. Primitive.prototype.destroy = function() {
  1864. var length;
  1865. var i;
  1866. this._sp = this._sp && this._sp.destroy();
  1867. this._spDepthFail = this._spDepthFail && this._spDepthFail.destroy();
  1868. var va = this._va;
  1869. length = va.length;
  1870. for (i = 0; i < length; ++i) {
  1871. va[i].destroy();
  1872. }
  1873. this._va = undefined;
  1874. var pickIds = this._pickIds;
  1875. length = pickIds.length;
  1876. for (i = 0; i < length; ++i) {
  1877. pickIds[i].destroy();
  1878. }
  1879. this._pickIds = undefined;
  1880. this._batchTable = this._batchTable && this._batchTable.destroy();
  1881. //These objects may be fairly large and reference other large objects (like Entities)
  1882. //We explicitly set them to undefined here so that the memory can be freed
  1883. //even if a reference to the destroyed Primitive has been kept around.
  1884. this._instanceIds = undefined;
  1885. this._perInstanceAttributeCache = undefined;
  1886. this._attributeLocations = undefined;
  1887. return destroyObject(this);
  1888. };
  1889. function setReady(primitive, frameState, state, error) {
  1890. primitive._error = error;
  1891. primitive._state = state;
  1892. frameState.afterRender.push(function() {
  1893. primitive._ready = primitive._state === PrimitiveState.COMPLETE || primitive._state === PrimitiveState.FAILED;
  1894. if (!defined(error)) {
  1895. primitive._readyPromise.resolve(primitive);
  1896. } else {
  1897. primitive._readyPromise.reject(error);
  1898. }
  1899. });
  1900. }
  1901. export default Primitive;