Primitive.js 80 KB

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