25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1496 lines
160KB

  1. /*
  2. * KNWebGLParticleObjects.js
  3. * Keynote HTML Player
  4. *
  5. * Created by Tungwei Cheng
  6. * Copyright (c) 2016-2018 Apple Inc. All rights reserved.
  7. */
  8. var kNumCameraShakePoints = 10;
  9. var kParticleSize = 16;
  10. var smokeImage = new Image();
  11. smokeImage.src = "data:image/png;base64,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";
  12. var speckImage = new Image();
  13. speckImage.src = "data:image/png;base64,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";
  14. var flameImage = new Image();
  15. flameImage.src = "data:image/png;base64,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";
  16. var fireworksImage = new Image();
  17. fireworksImage.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM3QzYxRTkxNTI4MTFFMEJCNUZCQkY4M0Q5QzA5QUUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM3QzYxRUExNTI4MTFFMEJCNUZCQkY4M0Q5QzA5QUUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzdDNjFFNzE1MjgxMUUwQkI1RkJCRjgzRDlDMDlBRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzdDNjFFODE1MjgxMUUwQkI1RkJCRjgzRDlDMDlBRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuKuqL4AAAJZSURBVHjazFfZcqMwEGRAxEfinP//jbtZXxAORarqYdsTCTsvCa7qEpijWz2aGSHFDT/vvdCpXLt9ulHEX3u33EjMo2Se9TTy8awQuUKeQmmEFIZ4pOMJORFyA3lJqMw5/0bCYM6zImSGnEkdjY6ECM1eiXtgoHESYkXIDHkF1MAdjSyiMOQfAR2NHa4NKREyQ+5AuALWwIrEsAAlbQMaoAU648YkQjK266wj4Qa4D9gCa1yvIGAASSQ9AceAM9CQGxfhYAFK7jDDNcgi8Y7wAEErI6AF2SFgTzhCUAOHehURBbjEimfrtyB9CngGdhC1xr0FXtqAbGPC480a0KyQwD29QMOhC48diIQvAa8Yn/CfhqEg+/fkjICspzXQ49qopM5UuFQI1IFI/oZxh5myA2fjykCLssWxhkD5vEsUHBuCBxA+gzzikaxWB86GXNeELsoa15UnuiA2BJyCK8qCexLymBFQm/VwwD2auqkClgxBSRXvztSADWFLz7OQTaJmODP7qZdYB2xGcPmtDRwRF5nrdtZfGllZ/PLPJdqpzzSXzoBnn7re2/JrWvWFACYd6WFb27W01onYn03p5fTruQKyCOsAz7ol0iNWNed5lxDwD8XoQL2ASzC7MTmQmn0HASdKJ679faYQRfI/Ae8QczDN6IsLqRCo9drZ9kilyuR5rhS/kwhtRrYRZUMwUAltTPXyVOGOM80okv4lAdwJ9f3/QxBbYuxKxoESRBXl7Eix/k47PplNycUecRkbkl/fki1iU7qIbfkiPkwW8Wm2iI/Tn/o8/xRgAC3fu+i/r3G+AAAAAElFTkSuQmCC";
  18. var fireworksCenterBurstImage = new Image();
  19. fireworksCenterBurstImage.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3NDBDQ0JGOTYzNTIxMUUyQjA3RUFENTVGMzUzRDEzNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo3NDBDQ0JGQTYzNTIxMUUyQjA3RUFENTVGMzUzRDEzNCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjc0MENDQkY3NjM1MjExRTJCMDdFQUQ1NUYzNTNEMTM0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjc0MENDQkY4NjM1MjExRTJCMDdFQUQ1NUYzNTNEMTM0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EpkdvgAAbEdJREFUeNrsXe3O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";
  20. var shimmerImage = new Image();
  21. shimmerImage.src = "data:image/png;base64,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";
  22. var sparkleImage = new Image();
  23. sparkleImage.src = "data:image/png;base64,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";
  24. var KNWebGLParticleSystem = Class.create({
  25. initialize: function(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture) {
  26. this.renderer = renderer;
  27. this.program = program;
  28. var gl = this.gl = this.renderer.gl;
  29. var uniforms = this.uniforms = program.uniforms;
  30. var attribs = this.attribs = program.attribs;
  31. // enables attribs and uniforms
  32. KNWebGLUtil.enableAttribs(gl, program)
  33. this.texture = texture;
  34. this.objectSize = objectSize;
  35. this.slideSize = slideSize;
  36. this.duration = duration;
  37. this.particleSize = particleSize;
  38. this.particleSystemSize = particleSystemSize;
  39. this.particleCount = particleSystemSize.width * particleSystemSize.height;
  40. this.particlesWide = particleSystemSize.width;
  41. this.particlesHigh = particleSystemSize.height;
  42. // array to store individual particle visibility within the particle system
  43. this.particleSystemVisibilities = [];
  44. // set to true by default
  45. this.shouldDraw = true;
  46. this.percentfinished = 0.0;
  47. },
  48. animationWillBeginWithContext: function() {
  49. var gl = this.gl;
  50. var uniforms = this.uniforms;
  51. var attribs = this.attribs;
  52. if (uniforms["SpeedMax"] !== undefined) {
  53. this._speedMax = this.speedMax();
  54. gl.uniform1f(uniforms["SpeedMax"], this._speedMax);
  55. }
  56. if (uniforms["RotationMax"] !== undefined) {
  57. this._rotationMax = this.rotationMax();
  58. gl.uniform1f(uniforms["RotationMax"], this._rotationMax);
  59. }
  60. if (uniforms["Duration"] !== undefined) {
  61. this._duration = this.duration / 1000;
  62. gl.uniform1f(uniforms["Duration"], this._duration);
  63. }
  64. var particleSize = this.particleSize;
  65. var objectSize = this.objectSize;
  66. var objectBoundsRect = CGRectMake(0, 0, objectSize.width, objectSize.height);
  67. var texWidth = objectSize.width;
  68. var texHeight = objectSize.height;
  69. var pixels;
  70. if (this.pixels) {
  71. // create framebuffer to read gl texture
  72. var fb = gl.createFramebuffer();
  73. pixels = new Uint8Array(texWidth * texHeight * 4);
  74. // bind the framebuffer for reading pixels
  75. gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  76. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);
  77. if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
  78. gl.readPixels(0, 0, texWidth, texHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  79. }
  80. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  81. }
  82. var isLookingAtObjectTexture = attribs["TexCoord"] !== undefined;
  83. gl.useProgram(this.program.shaderProgram);
  84. var attributeBuffers = this.attributeBuffers = {};
  85. attributeBuffers["Position"] = [];
  86. attributeBuffers["Center"] = [];
  87. attributeBuffers["TexCoord"] = [];
  88. attributeBuffers["ParticleTexCoord"] = [];
  89. attributeBuffers["Speed"] = [];
  90. attributeBuffers["Rotation"] = [];
  91. attributeBuffers["Scale"] = [];
  92. attributeBuffers["LifeSpan"] = [];
  93. attributeBuffers["Color"] = [];
  94. var numberOfVerticesPerParticle = this.numberOfVerticesPerParticle;
  95. for (var y = 0, particlesHigh = this.particlesHigh; y < particlesHigh; y++) {
  96. for (var x = 0, particlesWide = this.particlesWide; x < particlesWide; x++) {
  97. var indexPoint = WebGraphics.makePoint(x, y);
  98. var index = this.particlesWide * indexPoint.y + indexPoint.x;
  99. var vertIndex = index * numberOfVerticesPerParticle;
  100. var particleRect = CGRectMake(x * particleSize.width, y * particleSize.height, particleSize.width, particleSize.height);
  101. if (isLookingAtObjectTexture && (x === particlesWide - 1 || y === particlesHigh - 1)) {
  102. // Make sure we clip last row/column to actual bounds of object
  103. particleRect = CGRectIntersection(particleRect, objectBoundsRect);
  104. }
  105. var pixelParticleRect = particleRect;
  106. var visible = true;
  107. if (this.pixels) {
  108. var bytesPerRow = texWidth * 4;
  109. // add up color values in region
  110. var addingColor = WebGraphics.makePoint4D(0, 0, 0, 0);
  111. var attenuationCounter = 0;
  112. var maxXX = pixelParticleRect.origin.x + pixelParticleRect.size.width;
  113. var maxYY = pixelParticleRect.origin.y + pixelParticleRect.size.height;
  114. for (var yy = pixelParticleRect.origin.y; yy < maxYY; ++yy) {
  115. for (var xx = pixelParticleRect.origin.x; xx < maxXX; ++xx) {
  116. if (xx < texWidth && yy < texHeight) {
  117. // find pixel index from top because the object is flipped
  118. var index = (texHeight - yy - 1) * texWidth * 4 + xx * 4;
  119. // Make sure we're within the OpenGL texture bounds
  120. // (our total size can be a little bigger than the actual texture)
  121. if (attribs["Color"] !== undefined) {
  122. // attenuate color value by distance from center
  123. var attenuation = 1.0;
  124. if (pixelParticleRect.size.width > 1) {
  125. var xPos = 2 * (xx - pixelParticleRect.origin.x) / pixelParticleRect.size.width - 1;
  126. var yPos = 2 * (yy - pixelParticleRect.origin.y) / pixelParticleRect.size.height - 1;
  127. attenuation = (1 - xPos * xPos) + (1 - yPos * yPos);
  128. }
  129. var r = pixels[index];
  130. var g = pixels[index + 1];
  131. var b = pixels[index + 2];
  132. var a = pixels[index + 3];
  133. var thisPixel = WebGraphics.makePoint4D(r/255, g/255, b/255, a/255);
  134. if (thisPixel.w !== 0.0) {
  135. addingColor.x += attenuation * thisPixel.x / thisPixel.w;
  136. addingColor.y += attenuation * thisPixel.y / thisPixel.w;
  137. addingColor.z += attenuation * thisPixel.z / thisPixel.w;
  138. addingColor.w += attenuation * thisPixel.w;
  139. attenuationCounter += attenuation;
  140. }
  141. } else {
  142. // only care about alpha
  143. var a = pixels[index + 3] / 255;
  144. addingColor.w += a;
  145. }
  146. }
  147. }
  148. }
  149. // set visibility for the particle
  150. visible = addingColor.w > 0;
  151. this.particleSystemVisibilities.push(visible);
  152. if (attribs["Color"] !== undefined) {
  153. // set the color
  154. if (attenuationCounter == 0) {
  155. // If we never saw any pixels, we're just copying all zeroes into color
  156. attenuationCounter = 1;
  157. }
  158. var invAttenuationCounter = 1.0 / attenuationCounter;
  159. var theColor = WebGraphics.multiplyPoint4DByScalar(addingColor, invAttenuationCounter)
  160. var attributeBuffersColor = attributeBuffers["Color"];
  161. KNWebGLUtil.setPoint4DAtIndexForAttribute(theColor, vertIndex, attributeBuffersColor);
  162. KNWebGLUtil.setPoint4DAtIndexForAttribute(theColor, vertIndex + 1, attributeBuffersColor);
  163. KNWebGLUtil.setPoint4DAtIndexForAttribute(theColor, vertIndex + 2, attributeBuffersColor);
  164. KNWebGLUtil.setPoint4DAtIndexForAttribute(theColor, vertIndex + 3, attributeBuffersColor);
  165. }
  166. }
  167. if (this.willOverrideStartingPoints) {
  168. particleRect.origin = WebGraphics.setOrigin(particleRect.origin, this.startingPointAtIndexPoint(indexPoint));
  169. }
  170. var vertices = [];
  171. vertices[0] = WebGraphics.makePoint(particleRect.origin.x, particleRect.origin.y);
  172. if (numberOfVerticesPerParticle > 1) {
  173. vertices[1] = WebGraphics.makePoint(particleRect.origin.x + particleRect.size.width, particleRect.origin.y);
  174. vertices[2] = WebGraphics.makePoint(particleRect.origin.x + particleRect.size.width, particleRect.origin.y + particleRect.size.height);
  175. vertices[3] = WebGraphics.makePoint(particleRect.origin.x, particleRect.origin.y + particleRect.size.height);
  176. }
  177. for (var i = 0; i < numberOfVerticesPerParticle; i++) {
  178. KNWebGLUtil.setPoint2DAtIndexForAttribute(vertices[i], vertIndex + i, attributeBuffers["Position"]);
  179. }
  180. if (attribs["Center"] !== undefined) {
  181. var midX = particleRect.origin.x + (particleRect.size.width / 2);
  182. var midY = particleRect.origin.y + (particleRect.size.height / 2);
  183. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  184. WebGraphics.makePoint(midX, midY), vertIndex, attributeBuffers["Center"]);
  185. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  186. WebGraphics.makePoint(midX, midY), vertIndex + 1, attributeBuffers["Center"]);
  187. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  188. WebGraphics.makePoint(midX, midY), vertIndex + 2, attributeBuffers["Center"]);
  189. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  190. WebGraphics.makePoint(midX, midY), vertIndex + 3, attributeBuffers["Center"]);
  191. }
  192. if (attribs["TexCoord"] !== undefined) {
  193. for (var i = 0; i < numberOfVerticesPerParticle; i++) {
  194. var texCoord = WebGraphics.makePoint(vertices[i].x / objectSize.width, vertices[i].y / objectSize.height);
  195. KNWebGLUtil.setPoint2DAtIndexForAttribute(texCoord, vertIndex + i, attributeBuffers["TexCoord"]);
  196. }
  197. }
  198. if (attribs["ParticleTexCoord"] !== undefined) {
  199. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  200. WebGraphics.makePoint(0, 0), vertIndex, attributeBuffers["ParticleTexCoord"]);
  201. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  202. WebGraphics.makePoint(1, 0), vertIndex + 1, attributeBuffers["ParticleTexCoord"]);
  203. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  204. WebGraphics.makePoint(1, 1), vertIndex + 2, attributeBuffers["ParticleTexCoord"]);
  205. KNWebGLUtil.setPoint2DAtIndexForAttribute(
  206. WebGraphics.makePoint(0, 1), vertIndex + 3, attributeBuffers["ParticleTexCoord"]);
  207. }
  208. if (attribs["Speed"] !== undefined) {
  209. var speed = this.speedAtIndexPoint(indexPoint);
  210. KNWebGLUtil.setPoint3DAtIndexForAttribute(speed, vertIndex, attributeBuffers["Speed"]);
  211. KNWebGLUtil.setPoint3DAtIndexForAttribute(speed, vertIndex + 1, attributeBuffers["Speed"]);
  212. KNWebGLUtil.setPoint3DAtIndexForAttribute(speed, vertIndex + 2, attributeBuffers["Speed"]);
  213. KNWebGLUtil.setPoint3DAtIndexForAttribute(speed, vertIndex + 3, attributeBuffers["Speed"]);
  214. }
  215. if (attribs["Rotation"] !== undefined) {
  216. var rotation = this.rotationAtIndexPoint(indexPoint);
  217. KNWebGLUtil.setPoint3DAtIndexForAttribute(rotation, vertIndex, attributeBuffers["Rotation"]);
  218. KNWebGLUtil.setPoint3DAtIndexForAttribute(rotation, vertIndex + 1, attributeBuffers["Rotation"]);
  219. KNWebGLUtil.setPoint3DAtIndexForAttribute(rotation, vertIndex + 2, attributeBuffers["Rotation"]);
  220. KNWebGLUtil.setPoint3DAtIndexForAttribute(rotation, vertIndex + 3, attributeBuffers["Rotation"]);
  221. }
  222. if (attribs["Scale"] !== undefined) {
  223. var scale = this.scaleAtIndexPoint(indexPoint);
  224. KNWebGLUtil.setFloatAtIndexForAttribute(scale, vertIndex, attributeBuffers["Scale"]);
  225. KNWebGLUtil.setFloatAtIndexForAttribute(scale, vertIndex + 1, attributeBuffers["Scale"]);
  226. KNWebGLUtil.setFloatAtIndexForAttribute(scale, vertIndex + 2, attributeBuffers["Scale"]);
  227. KNWebGLUtil.setFloatAtIndexForAttribute(scale, vertIndex + 3, attributeBuffers["Scale"]);
  228. }
  229. if (attribs["LifeSpan"] !== undefined) {
  230. var lifeSpan = this.lifeSpanAtIndexPoint(indexPoint);
  231. KNWebGLUtil.setPoint2DAtIndexForAttribute(lifeSpan, vertIndex, attributeBuffers["LifeSpan"]);
  232. KNWebGLUtil.setPoint2DAtIndexForAttribute(lifeSpan, vertIndex + 1, attributeBuffers["LifeSpan"]);
  233. KNWebGLUtil.setPoint2DAtIndexForAttribute(lifeSpan, vertIndex + 2, attributeBuffers["LifeSpan"]);
  234. KNWebGLUtil.setPoint2DAtIndexForAttribute(lifeSpan, vertIndex + 3, attributeBuffers["LifeSpan"]);
  235. }
  236. if (attribs["Color"] !== undefined && this.willOverrideColors) {
  237. var color = this.colorAtIndexPoint(indexPoint);
  238. KNWebGLUtil.setPoint4DAtIndexForAttribute(color, vertIndex, attributeBuffers["Color"]);
  239. KNWebGLUtil.setPoint4DAtIndexForAttribute(color, vertIndex + 1, attributeBuffers["Color"]);
  240. KNWebGLUtil.setPoint4DAtIndexForAttribute(color, vertIndex + 2, attributeBuffers["Color"]);
  241. KNWebGLUtil.setPoint4DAtIndexForAttribute(color, vertIndex + 3, attributeBuffers["Color"]);
  242. }
  243. }
  244. }
  245. var indexCounter = 0;
  246. var elementArray = this.elementArray = [];
  247. for (var i = 0; i < this.particleCount; i++) {
  248. elementArray[indexCounter++] = 4 * i + 0;
  249. elementArray[indexCounter++] = 4 * i + 1;
  250. elementArray[indexCounter++] = 4 * i + 2;
  251. // second triangle
  252. elementArray[indexCounter++] = 4 * i + 0;
  253. elementArray[indexCounter++] = 4 * i + 2;
  254. elementArray[indexCounter++] = 4 * i + 3;
  255. }
  256. this.buffer = {};
  257. KNWebGLUtil.bindAllAvailableAttributesToBuffers(gl, attribs, attributeBuffers, {
  258. "LifeSpan": 2,
  259. "Scale": 1,
  260. "Rotation": 3,
  261. "Speed": 3,
  262. "ParticleTexCoord": 2,
  263. "TexCoord": 2,
  264. "Center": 2,
  265. "Position": 2,
  266. "Color": 4
  267. }, this.buffer,
  268. gl.DYNAMIC_DRAW);
  269. this.elementArrayBuffer = gl.createBuffer();
  270. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementArrayBuffer);
  271. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elementArray), gl.DYNAMIC_DRAW);
  272. if (this.uniforms["Texture"]) {
  273. gl.uniform1i(this.uniforms["Texture"], 0);
  274. }
  275. if (this.uniforms["ParticleTexture"]) {
  276. gl.uniform1i(this.uniforms["ParticleTexture"], 0);
  277. }
  278. },
  279. drawFrame: function(percent, opacity) {
  280. var gl = this.gl;
  281. var program = this.program;
  282. var uniforms = this.uniforms;
  283. this.percentfinished = percent;
  284. gl.useProgram(program.shaderProgram);
  285. gl.bindTexture(gl.TEXTURE_2D, this.texture);
  286. gl.uniform1f(uniforms["Percent"], percent);
  287. gl.uniform1f(uniforms["Opacity"], opacity);
  288. KNWebGLUtil.bindAllAvailableAttributesToBuffers(gl, this.attribs, this.attributeBuffers, {
  289. "LifeSpan": 2,
  290. "Scale": 1,
  291. "Rotation": 3,
  292. "Speed": 3,
  293. "ParticleTexCoord": 2,
  294. "TexCoord": 2,
  295. "Center": 2,
  296. "Position": 2,
  297. "Color": 4
  298. }, this.buffer,
  299. gl.DYNAMIC_DRAW);
  300. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementArrayBuffer);
  301. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.elementArray), gl.DYNAMIC_DRAW);
  302. this.draw();
  303. },
  304. draw: function() {
  305. var gl = this.gl;
  306. gl.drawElements(gl.TRIANGLES, this.elementArray.length, gl.UNSIGNED_SHORT, 0);
  307. },
  308. setColor: function(color) {
  309. var gl = this.gl;
  310. gl.useProgram(this.program.shaderProgram);
  311. gl.uniform4fv(this.uniforms["Color"], color);
  312. },
  313. setMVPMatrix: function(MVPMatrix) {
  314. var gl = this.gl;
  315. gl.useProgram(this.program.shaderProgram);
  316. gl.uniformMatrix4fv(this.uniforms["MVPMatrix"], false, MVPMatrix);
  317. },
  318. indexFromPoint: function(point) {
  319. return this.particlesWide * point.y + point.x;
  320. },
  321. particleSystemSizeWithRequestedNumber: function(requestedNumParticles, objectSize) {
  322. var maxNumParticles = 65535 / this.numberOfVerticesPerParticle;
  323. requestedNumParticles = Math.min(requestedNumParticles, maxNumParticles);
  324. if ((objectSize.width === 0 && objectSize.height === 0) || this.willOverrideStartingPoints || requestedNumParticles === 1) {
  325. return WebGraphics.makeSize(requestedNumParticles, 1);
  326. }
  327. if (requestedNumParticles >= objectSize.width * objectSize.height) {
  328. return objectSize;
  329. }
  330. if (requestedNumParticles < 1) {
  331. requestedNumParticles = 1;
  332. return WebGraphics.makeSize(requestedNumParticles, 1);
  333. }
  334. var currentNumParticles = 0, prevNumParticles = 0;
  335. var particleSize = Math.round(Math.sqrt(objectSize.width * objectSize.height));
  336. //find best fit for number of particles
  337. currentNumParticles = Math.ceil(objectSize.width / particleSize) * Math.ceil(objectSize.height / particleSize);
  338. if (currentNumParticles === requestedNumParticles) {
  339. return WebGraphics.makeSize(particleSize, particleSize);
  340. }
  341. if (currentNumParticles < requestedNumParticles) {
  342. do {
  343. prevNumParticles = currentNumParticles;
  344. particleSize--;
  345. currentNumParticles = Math.ceil(objectSize.width/particleSize) * Math.ceil(objectSize.height/particleSize);
  346. } while (currentNumParticles < requestedNumParticles && particleSize > 2);
  347. if (particleSize <= 2.0) {
  348. return WebGraphics.makeSize(Math.ceil(objectSize.width / 2), Math.ceil(objectSize.height / 2));
  349. }
  350. if (Math.abs(currentNumParticles - requestedNumParticles) < Math.abs(prevNumParticles - requestedNumParticles)) {
  351. return WebGraphics.makeSize(Math.ceil(objectSize.width / particleSize), Math.ceil(objectSize.height / particleSize));
  352. } else {
  353. return WebGraphics.makeSize(Math.ceil(objectSize.width / (particleSize + 1)), Math.ceil(objectSize.height / (particleSize + 1)));
  354. }
  355. } else {
  356. do {
  357. prevNumParticles = currentNumParticles;
  358. particleSize++;
  359. currentNumParticles = Math.ceil(objectSize.width / particleSize) * Math.ceil(objectSize.height / particleSize);
  360. } while (currentNumParticles > requestedNumParticles && particleSize > 2);
  361. if (particleSize <= 2.0) {
  362. return WebGraphics.makeSize(Math.ceil(objectSize.width / 2), Math.ceil(objectSize.height / 2));
  363. }
  364. if (Math.abs(currentNumParticles - requestedNumParticles) < Math.abs(prevNumParticles - requestedNumParticles)) {
  365. return WebGraphics.makeSize(Math.ceil(objectSize.width / particleSize), Math.ceil(objectSize.height / particleSize));
  366. } else {
  367. return WebGraphics.makeSize(Math.ceil(objectSize.width / (particleSize + 1)), Math.ceil(objectSize.height / (particleSize + 1)));
  368. }
  369. }
  370. },
  371. point3DRandomDirection: function() {
  372. var u = WebGraphics.randomBetween(-1.0, 1.0);
  373. var theta = WebGraphics.randomBetween(0, 2.0 * Math.PI);
  374. var prefix = Math.sqrt(1.0 - u * u);
  375. var result = WebGraphics.makePoint3D(prefix * Math.cos(theta), prefix * Math.sin(theta), u);
  376. return result;
  377. }
  378. });
  379. var KNWebGLBuildAnvilSmokeSystem = Class.create(KNWebGLParticleSystem, {
  380. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture) {
  381. this.willOverrideStartingPoints = true;
  382. // number of vertices per particle
  383. this.numberOfVerticesPerParticle = 4;
  384. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  385. this.setupWithTexture();
  386. },
  387. setupWithTexture: function() {
  388. this.animationWillBeginWithContext();
  389. },
  390. startingPointAtIndexPoint: function(indexPoint) {
  391. var index = this.indexFromPoint(indexPoint);
  392. return WebGraphics.makePoint(index / this.particleCount * this.objectSize.width - kParticleSize / 2, kParticleSize / 2);
  393. },
  394. speedAtIndexPoint: function(point) {
  395. var xDirection = (2 * this.indexFromPoint(point)) / (this.particleCount) -1;
  396. xDirection = (xDirection < 0 ? -1 : 1) * Math.sqrt(Math.abs(xDirection));
  397. //we've adjusted these values specifically for WebGL
  398. var yDirection = (Math.abs(xDirection) + 0.25) * WebGraphics.randomBetween(-1.0, 0.1);
  399. xDirection *= WebGraphics.randomBetween(0.25, 1);
  400. var speed = WebGraphics.makePoint3D(
  401. this.p_anvilGlobalScale() * 5.6 * xDirection,
  402. this.p_anvilGlobalScale() * 5 * -yDirection, 0);
  403. return speed;
  404. },
  405. rotationAtIndexPoint: function(point) {
  406. var xDirection = (2 * this.indexFromPoint(point)) / (this.particleCount) - 1;
  407. var thisRotation = xDirection * WebGraphics.randomBetween(0.5, 1) * Math.PI;
  408. thisRotation *= this.duration / 1000;
  409. return WebGraphics.makePoint3D(0, 0, thisRotation);
  410. },
  411. scaleAtIndexPoint: function(indexPoint) {
  412. var scale = Math.abs(((2.0 * this.indexFromPoint(indexPoint)) / this.particleCount) - 1.0);
  413. scale += 1.25;
  414. var randVal = WebGraphics.randomBetween(0, 1);
  415. randVal *= randVal * randVal;
  416. scale *= WebGraphics.mix(1, 2.5, randVal);
  417. scale *= (this.p_anvilGlobalScale() / kParticleSize);
  418. return scale;
  419. },
  420. lifeSpanAtIndexPoint: function(indexPoint) {
  421. return WebGraphics.makePoint(0, (this.duration / 1000) * WebGraphics.randomBetween(0.15, 1));
  422. },
  423. p_anvilGlobalScale: function() {
  424. return WebGraphics.mix(1.25, 0.75, this.objectSize.width / this.slideSize.width) * (this.objectSize.width/7);
  425. }
  426. });
  427. var KNWebGLBuildAnvilSpeckSystem = Class.create(KNWebGLParticleSystem, {
  428. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture) {
  429. this.willOverrideStartingPoints = true;
  430. // number of vertices per particle
  431. this.numberOfVerticesPerParticle = 4;
  432. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  433. this.setupWithTexture();
  434. },
  435. setupWithTexture: function() {
  436. this.animationWillBeginWithContext();
  437. },
  438. startingPointAtIndexPoint: function(indexPoint) {
  439. var index = this.indexFromPoint(indexPoint);
  440. return WebGraphics.makePoint(index/this.particleCount * this.objectSize.width - kParticleSize/2, kParticleSize/2);
  441. },
  442. speedAtIndexPoint: function(point) {
  443. var speed = WebGraphics.makePoint3D(0, 0, 0);
  444. var index = this.indexFromPoint(point);
  445. speed.x = 2 * index / this.particleCount - 1;
  446. speed.y = WebGraphics.randomBetween(0.2, 1);
  447. if (index % 3 != 1) {
  448. speed.z = 0.2;
  449. speed.y *= 0.025 * (WebGraphics.randomBetween(0,1) < 0.5 ? -1 : 1);
  450. speed.x *= 10;
  451. speed.y *= 10;
  452. } else {
  453. speed.z = 1.0;
  454. }
  455. speed.x *= this.p_anvilGlobalScale() * 5.25;
  456. speed.y *= this.p_anvilGlobalScale() * 4; //only difference is our coordinate system is setup reversed to the desktop, so we need to multiply by -4 instead of 4
  457. return speed;
  458. },
  459. rotationAtIndexPoint: function(point) {
  460. var xDirection = (2 * this.indexFromPoint(point)) / (this.particleCount) - 1;
  461. var thisRotation = xDirection * WebGraphics.randomBetween(0.5, 1) * Math.PI;
  462. thisRotation *= this.duration / 1000;
  463. return WebGraphics.makePoint3D(0, 0, thisRotation);
  464. },
  465. scaleAtIndexPoint: function(indexPoint) {
  466. var index = this.indexFromPoint(indexPoint);
  467. var scale = WebGraphics.randomBetween(3, 5);
  468. if (index % 3 != 1) {
  469. scale *= 3;
  470. }
  471. scale *= (this.p_anvilGlobalScale() / kParticleSize);
  472. return scale;
  473. },
  474. lifeSpanAtIndexPoint: function(indexPoint) {
  475. var index = this.indexFromPoint(indexPoint);
  476. var lifeSpan = WebGraphics.makePoint(0, Math.min(1, this.duration/1000) * WebGraphics.randomBetween(0.2, 0.5));
  477. if (index % 3 != 1) {
  478. lifeSpan.y *= 10;
  479. }
  480. return lifeSpan;
  481. },
  482. p_anvilGlobalScale: function() {
  483. return WebGraphics.mix(1.25, 0.75, this.objectSize.width / this.slideSize.width)*(this.objectSize.width/7);
  484. }
  485. });
  486. var KNWebGLBuildFlameSystem = Class.create(KNWebGLParticleSystem, {
  487. initialize: function($super, renderer, program, objectSize, slideSize, duration, numParticles, texture) {
  488. // overwrite starting point
  489. this.willOverrideStartingPoints = true;
  490. // number of vertices per particle
  491. this.numberOfVerticesPerParticle = 4;
  492. var width = objectSize.width;
  493. var height = objectSize.height;
  494. var particleSystemSize = this.particleSystemSizeWithRequestedNumber(numParticles, WebGraphics.makeSize(width, height));
  495. var particleSize = WebGraphics.makeSize(Math.ceil(width / particleSystemSize.width), Math.ceil(height / particleSystemSize.height));
  496. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  497. },
  498. p_setupParticleDataWithTexture: function(textureInfo) {
  499. var gl = this.gl;
  500. var width = textureInfo.width;
  501. var height = textureInfo.height;
  502. // create framebuffer to read gl texture
  503. var fb = gl.createFramebuffer();
  504. var pixels = new Uint8Array(width * height * 4);
  505. // bind the framebuffer for reading pixels
  506. gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  507. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureInfo.texture, 0);
  508. if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
  509. gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  510. }
  511. var minPoint = {
  512. "x": width,
  513. "y": height
  514. };
  515. var maxPoint = {
  516. "x": 0,
  517. "y": 0
  518. };
  519. // Want to start the flames at the alpha-bottom of the image, not the absolute bottom
  520. var bottomRow = [];
  521. var bottomRowCount = width;
  522. var actualSize = {};
  523. for (var i = 0; i < width * 4; i += 4) {
  524. var x = i / 4;
  525. var minY = Number.MAX_VALUE;
  526. var maxY = 0;
  527. var hasNonTransparentPixels = false;
  528. var thisPoint = {
  529. "x": x / width,
  530. "y": -1
  531. };
  532. // search from top because the object is flipped
  533. for (var j = height - 1; j >= 0; j--) {
  534. var alphaIndex = x * 4 + j * (width) * 4 + 3;
  535. var y = height - j;
  536. if (pixels[alphaIndex]/255 > 0.1) {
  537. minY = Math.min(y, minY);
  538. maxY = Math.max(y, maxY);
  539. hasNonTransparentPixels = true;
  540. }
  541. }
  542. if (hasNonTransparentPixels) {
  543. thisPoint.y = maxY / height;
  544. minPoint.x = Math.min(minPoint.x, x);
  545. maxPoint.x = Math.max(maxPoint.x, x);
  546. minPoint.y = Math.min(minPoint.y, minY);
  547. maxPoint.y = Math.max(maxPoint.y, maxY);
  548. }
  549. bottomRow[x] = thisPoint;
  550. }
  551. actualSize = {
  552. width: maxPoint.x - minPoint.x,
  553. height: maxPoint.y - minPoint.y
  554. };
  555. this._actualSize = actualSize;
  556. this._bottomRow = bottomRow;
  557. this._bottomRowCount = bottomRowCount;
  558. // unbind the framebuffer
  559. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  560. this.animationWillBeginWithContext();
  561. var positionBuffer = this.attributeBuffers["Position"];
  562. var centerBuffer = this.attributeBuffers["Center"];
  563. // adjust vertices according to starting scale
  564. var minSide = this._actualSize.height / 2.0;
  565. var numberOfVerticesPerParticle = this.numberOfVerticesPerParticle;
  566. for (var index = 0, length = this.particleCount; index < length; index++) {
  567. var vertIndex = index * numberOfVerticesPerParticle;
  568. var origin = {
  569. "x": positionBuffer[vertIndex*2],
  570. "y": positionBuffer[vertIndex*2 + 1]
  571. };
  572. origin.x -= minSide / 2;
  573. origin.y -= minSide / 2;
  574. var newRect = WebGraphics.makeRect(origin.x, origin.y, minSide, minSide);
  575. var center = WebGraphics.makePoint(origin.x + minSide/2, origin.y + minSide/2);
  576. KNWebGLUtil.setPoint2DAtIndexForAttribute(WebGraphics.makePoint(newRect.x, newRect.y), vertIndex, positionBuffer);
  577. KNWebGLUtil.setPoint2DAtIndexForAttribute(WebGraphics.makePoint(newRect.x + newRect.width, newRect.y), vertIndex + 1, positionBuffer);
  578. KNWebGLUtil.setPoint2DAtIndexForAttribute(WebGraphics.makePoint(newRect.x + newRect.width, newRect.y + newRect.height), vertIndex + 2, positionBuffer);
  579. KNWebGLUtil.setPoint2DAtIndexForAttribute(WebGraphics.makePoint(newRect.x, newRect.y + newRect.height), vertIndex + 3, positionBuffer);
  580. for (var i = 0; i < 4; i++) {
  581. KNWebGLUtil.setPoint2DAtIndexForAttribute(center, vertIndex + i, centerBuffer);
  582. }
  583. }
  584. },
  585. startingPointAtIndexPoint: function(indexPoint) {
  586. var x = 0;
  587. var y = 0;
  588. var foundY = false;
  589. for (var i = 0; i < this._bottomRowCount; i++) {
  590. // at least one row has y value not equal to -1
  591. if (this._bottomRow[i].y !== -1) {
  592. foundY = true;
  593. break;
  594. }
  595. }
  596. if (this._bottomRow && foundY) {
  597. do {
  598. var index = WebGraphics.randomBetween(0, this._bottomRowCount - 1);
  599. index = Math.round(index);
  600. x = this._bottomRow[index].x;
  601. y = this._bottomRow[index].y;
  602. } while (y === -1);
  603. }
  604. var positionPoint = {
  605. "x": x * this.objectSize.width,
  606. "y": y * this.objectSize.height
  607. };
  608. return positionPoint;
  609. },
  610. speedAtIndexPoint: function(indexPoint) {
  611. var index = this.indexFromPoint(indexPoint) * 4;
  612. var yPos = this.attributeBuffers["Position"][index*2 + 1];
  613. yPos = Math.min(yPos, this._actualSize.height);
  614. var maxUp = (this._actualSize.height * 0.2 + 0.9 * yPos) * (1.0 + WebGraphics.randomBetween(0.0, 0.1));
  615. var result = WebGraphics.makePoint3D(0, maxUp, 0);
  616. result = WebGraphics.multiplyPoint3DByScalar(result, 1.0 / this.speedMax());
  617. return result;
  618. },
  619. speedMax: function() {
  620. return this._actualSize.height * 1.1 * 1.1;
  621. },
  622. lifeSpanAtIndexPoint: function(indexPoint) {
  623. // CONSTANTS
  624. var maxParticleLife = Math.min(1.0, 1.0 / Math.max(2, this._duration));
  625. var thisParticleLife = maxParticleLife * WebGraphics.randomBetween(0.8, 1.0);
  626. // more at beginning
  627. var time = this.indexFromPoint(indexPoint) / this.particleCount;
  628. time = time * time * 0.25 + time * 0.75;
  629. time *= 1.0 - thisParticleLife;
  630. var lifeSpan = WebGraphics.makePoint(time, thisParticleLife);
  631. return lifeSpan;
  632. },
  633. rotationAtIndexPoint: function(indexPoint) {
  634. var rotation = WebGraphics.makePoint3D(WebGraphics.randomBetween(-1.0, 1.0), 0, WebGraphics.randomBetween(-1.0, 1.0));
  635. return rotation;
  636. },
  637. rotationMax: function() {
  638. return Math.PI * 2;
  639. }
  640. });
  641. var KNWebGLBuildConfettiSystem = Class.create(KNWebGLParticleSystem, {
  642. initialize: function($super, renderer, program, objectSize, slideSize, duration, numParticles, texture) {
  643. this.willOverrideStartingPoints = false;
  644. // number of vertices per particle
  645. this.numberOfVerticesPerParticle = 4;
  646. var width = objectSize.width;
  647. var height = objectSize.height;
  648. var particleSystemSize = this.particleSystemSizeWithRequestedNumber(numParticles, WebGraphics.makeSize(width, height));
  649. var particleSize = WebGraphics.makeSize(Math.ceil(width / particleSystemSize.width), Math.ceil(height / particleSystemSize.height));
  650. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  651. this.setupWithTexture();
  652. },
  653. setupWithTexture: function() {
  654. this.animationWillBeginWithContext();
  655. },
  656. startingPointAtIndexPoint: function(indexPoint) {
  657. var index = this.indexFromPoint(indexPoint);
  658. return WebGraphics.makePoint(index / this.particleCount * this.objectSize.width - kParticleSize / 2, kParticleSize / 2);
  659. },
  660. speedAtIndexPoint: function(point) {
  661. var speedMax = 0.025;
  662. var speedRandMax = speedMax * 20;
  663. var speedAdjust = this.objectSize.width / this.slideSize.width * this.objectSize.height / this.slideSize.height;
  664. speedAdjust = Math.sqrt(speedAdjust);
  665. speedAdjust = 1.0 - speedAdjust * 0.75;
  666. speedMax *= speedAdjust;
  667. speedRandMax *= speedAdjust;
  668. var minSide = Math.min(this.objectSize.height, this.objectSize.width);
  669. var theRandSpeed = minSide * speedRandMax;
  670. var theSpeed = minSide * speedMax;
  671. var maxRadiusSquared = (this.particleSystemSize.width * this.particleSystemSize.width + this.particleSystemSize.height * this.particleSystemSize.height) / 4.0;
  672. var randSpeed = WebGraphics.makePoint3D(WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1));
  673. randSpeed.z = -Math.abs(randSpeed.z);
  674. randSpeed = WebGraphics.multiplyPoint3DByScalar(randSpeed, theRandSpeed);
  675. var vector = WebGraphics.makePoint3D(point.x - this.particlesWide / 2.0, point.y - this.particlesHigh / 2.0, 0);
  676. var radiusSquared = (vector.x * vector.x + vector.y * vector.y);
  677. vector.z = Math.sqrt(maxRadiusSquared - radiusSquared);
  678. var speed = WebGraphics.multiplyPoint3DByScalar(vector, theSpeed);
  679. speed = WebGraphics.addPoint3DToPoint3D(speed, randSpeed);
  680. return speed;
  681. },
  682. rotationAtIndexPoint: function(point) {
  683. var rotationMax = 8.0 * Math.PI;
  684. var rotation = WebGraphics.makePoint3D(WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1));
  685. return WebGraphics.multiplyPoint3DByScalar(rotation, rotationMax);
  686. },
  687. scaleAtIndexPoint: function(indexPoint) {
  688. return 1.0;
  689. }
  690. });
  691. var KNWebGLBuildDiffuseSystem = Class.create(KNWebGLParticleSystem, {
  692. initialize: function($super, renderer, program, objectSize, slideSize, duration, numParticles, texture, l2r) {
  693. this.willOverrideStartingPoints = false;
  694. // number of vertices per particle
  695. this.numberOfVerticesPerParticle = 4;
  696. // set direction
  697. this.l2r = l2r;
  698. var width = objectSize.width;
  699. var height = objectSize.height;
  700. var particleSystemSize = this.particleSystemSizeWithRequestedNumber(numParticles, WebGraphics.makeSize(width, height));
  701. var particleSize = WebGraphics.makeSize(Math.ceil(width / particleSystemSize.width), Math.ceil(height / particleSystemSize.height));
  702. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  703. this.setupWithTexture();
  704. },
  705. setupWithTexture: function() {
  706. this.animationWillBeginWithContext();
  707. },
  708. speedAtIndexPoint: function(indexPoint) {
  709. var l2r = this.l2r;
  710. //more random towards center
  711. var randDirection = WebGraphics.makePoint3D(WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1));
  712. var vertical = 2 * indexPoint.y / this.particleSystemSize.height - 1.0;
  713. randDirection = WebGraphics.multiplyPoint3DByScalar(randDirection, (1.1 - vertical * vertical) * 8);
  714. //actual direction based on position of fragment height
  715. var startDirection = WebGraphics.makePoint3D((2 - Math.abs(vertical)) * (l2r ? -1: 1), vertical * 2, 0);
  716. startDirection = WebGraphics.multiplyPoint3DByScalar(startDirection, 5.0);
  717. var theDirection = WebGraphics.addPoint3DToPoint3D(startDirection, randDirection);
  718. theDirection = WebGraphics.point3DNormalize(theDirection);
  719. return theDirection;
  720. },
  721. speedMax: function() {
  722. var speed = this.objectSize.height * 1.5 / Math.sqrt(this.duration / 1000);
  723. return speed;
  724. },
  725. rotationAtIndexPoint: function(indexPoint) {
  726. var rotation = WebGraphics.makePoint3D(WebGraphics.randomBetween(-1, 1), WebGraphics.randomBetween(-1, 1), 0);
  727. return rotation;
  728. },
  729. rotationMax: function() {
  730. var rotationMax = 8.0 * Math.PI;
  731. return rotationMax;
  732. },
  733. lifeSpanAtIndexPoint: function(indexPoint) {
  734. var l2r = this.l2r;
  735. var width = this.particleSystemSize.width;
  736. var maxParticleLife = WebGraphics.clamp(0.8 / (this.duration / 1000), 0.1, 0.9);
  737. var time = (l2r ? (width - indexPoint.x): indexPoint.x) / width;
  738. time *= (1 - maxParticleLife);
  739. var lifeSpan = WebGraphics.makePoint(time, maxParticleLife);
  740. return lifeSpan;
  741. }
  742. });
  743. var KNWebGLBuildFireworksSystem = Class.create(KNWebGLParticleSystem, {
  744. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture) {
  745. // override starting point
  746. this.willOverrideStartingPoints = true;
  747. // override colors
  748. this.willOverrideColors = true;
  749. // number of vertices per particle
  750. this.numberOfVerticesPerParticle = 4;
  751. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  752. },
  753. setupWithTexture: function(textureInfo) {
  754. var gl = this.gl;
  755. var width = textureInfo.width;
  756. var height = textureInfo.height;
  757. var val1 = -Math.min(this.objectSize.height, this.slideSize.height / 10);
  758. var val2 = WebGraphics.randomBetween(val1, this.objectSize.height)
  759. this._startingPoint = WebGraphics.makePoint(this.fireworkStartingPositionX * this.objectSize.width, val2);
  760. // Initialize random color
  761. var startColor = WebGraphics.colorWithHSBA(WebGraphics.randomBetween(0, 1), 1, 1, 1);
  762. this._startingColorRGB = WebGraphics.makePoint3D(startColor.red, startColor.green, startColor.blue);
  763. this.animationWillBeginWithContext();
  764. },
  765. startingPointAtIndexPoint: function(indexPoint) {
  766. return this._startingPoint;
  767. },
  768. colorAtIndexPoint: function(indexPoint) {
  769. var randomColor = this.point3DRandomDirection();
  770. var randomColorResult = WebGraphics.multiplyPoint3DByScalar(randomColor, this.colorRandomness);
  771. var color = WebGraphics.addPoint3DToPoint3D(this._startingColorRGB, randomColorResult);
  772. color.x = WebGraphics.clamp(color.x, 0, 1);
  773. color.y = WebGraphics.clamp(color.y, 0, 1);
  774. color.z = WebGraphics.clamp(color.z, 0, 1);
  775. var result = {
  776. "x": color.x,
  777. "y": color.y,
  778. "z": color.z,
  779. "w": 1
  780. };
  781. return result;
  782. },
  783. speedAtIndexPoint: function(indexPoint) {
  784. var speed = this.point3DRandomDirection();
  785. var randomSpeed = WebGraphics.randomBetween(0.8, 1.0);
  786. var result = WebGraphics.multiplyPoint3DByScalar(speed, randomSpeed);
  787. return result;
  788. },
  789. speedMax: function() {
  790. return this.maxDistance;
  791. },
  792. scaleAtIndexPoint: function(indexPoint) {
  793. var scale = WebGraphics.randomBetween(this.randomParticleSizeMinMax.width, this.randomParticleSizeMinMax.height);
  794. return scale;
  795. },
  796. lifeSpanAtIndexPoint: function(indexPoint) {
  797. var lifeSpan = WebGraphics.makePoint(0, WebGraphics.randomBetween(this.lifeSpanMinDuration, 1.0));
  798. return lifeSpan;
  799. }
  800. });
  801. var KNWebGLBuildShimmerSystem = Class.create(KNWebGLParticleSystem, {
  802. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture) {
  803. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  804. },
  805. speedMax: function() {
  806. var sqrtArea = Math.sqrt(this.objectSize.width * this.objectSize.height);
  807. var result = sqrtArea * 0.075;
  808. return result;
  809. },
  810. speedAtIndexPoint: function(indexPoint) {
  811. var speed = this.point3DRandomDirection();
  812. speed.z = 0;
  813. return speed;
  814. }
  815. });
  816. var KNWebGLBuildShimmerObjectSystem = Class.create(KNWebGLBuildShimmerSystem, {
  817. initialize: function($super, renderer, program, objectSize, slideSize, duration, numParticles, texture, direction) {
  818. // override starting point
  819. this.willOverrideStartingPoints = false;
  820. // override colors
  821. this.willOverrideColors = false;
  822. // number of vertices per particle
  823. this.numberOfVerticesPerParticle = 4;
  824. // require setting color pixels
  825. this.pixels = true;
  826. // set direction
  827. this.direction = direction;
  828. var width = objectSize.width;
  829. var height = objectSize.height;
  830. var particleSystemSize = this.particleSystemSizeWithRequestedNumber(numParticles, WebGraphics.makeSize(width, height));
  831. var particleSize = WebGraphics.makeSize(Math.ceil(width / particleSystemSize.width), Math.ceil(height / particleSystemSize.height));
  832. // call KNWebGLBuildShimmerSystem initialize method
  833. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture, direction);
  834. this.setupWithTexture();
  835. },
  836. setupWithTexture: function() {
  837. this.animationWillBeginWithContext();
  838. },
  839. drawGLSLWithPercent: function(percent, particleOpacity, rotation, clockwise) {
  840. var delayedPercent = Math.max(0.0, percent * 1.1 - 0.1);
  841. var origTexPercent = 1.0 - Math.min(1.0, TSDMixFloats(5.0 * percent, percent * percent, percent));
  842. // Rotation Matrix
  843. var angle = delayedPercent * (clockwise ? 1 : -1) * 2;
  844. var rotMatrix = CGAffineTransformMakeRotation(angle);
  845. var mat3 = WebGraphics.makeMat3WithAffineTransform(rotMatrix);
  846. // set mat3 uniform for RotationMatrix
  847. this.gl.uniformMatrix3fv(this.uniforms["RotationMatrix"], false, mat3);
  848. // draw GLSL with percent
  849. this.drawFrame(delayedPercent, particleOpacity * origTexPercent);
  850. }
  851. });
  852. var KNWebGLBuildShimmerParticleSystem = Class.create(KNWebGLBuildShimmerSystem, {
  853. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, objectSystem, texture, direction) {
  854. // override starting point
  855. this.willOverrideStartingPoints = true;
  856. // override colors
  857. this.willOverrideColors = true;
  858. // number of vertices per particle
  859. this.numberOfVerticesPerParticle = 4;
  860. // set direction
  861. this.direction = direction;
  862. // object system particle count
  863. this.objectSystem = objectSystem;
  864. // object system vertex count
  865. this.objectSystemVertexCount = objectSystem.particleCount * 4;
  866. var kNumHullPoints = this.kNumHullPoints = 20
  867. //beginning of width of bottom spire on x-axis
  868. var kSpireMinW = 0.48828125;
  869. //beginning of height of bottom spire on y-axis
  870. var kSpireMinH = 0.02;
  871. //top of height of bottom spire on y-axis
  872. var kSpireMaxH = 0.3;
  873. this.p_particleHullArray = [
  874. // center quad
  875. { x: kSpireMaxH, y: kSpireMaxH },
  876. { x: 1 - kSpireMaxH, y: kSpireMaxH },
  877. { x: 1 - kSpireMaxH, y: 1 - kSpireMaxH },
  878. { x: kSpireMaxH, y: 1 - kSpireMaxH },
  879. // top quad
  880. { x: kSpireMinW, y: 1 - kSpireMaxH },
  881. { x: 1 - kSpireMinW, y: 1 - kSpireMaxH },
  882. { x: 1 - kSpireMinW, y: 1 - kSpireMinH },
  883. { x: kSpireMinW, y: 1 - kSpireMinH },
  884. // right quad
  885. { x: 1 - kSpireMaxH, y: 1 - kSpireMinW },
  886. { x: 1 - kSpireMinH, y: 1 - kSpireMinW },
  887. { x: 1 - kSpireMinH, y: kSpireMinW },
  888. { x: 1 - kSpireMaxH, y: kSpireMinW },
  889. // bottom quad
  890. { x: kSpireMinW, y: kSpireMinH },
  891. { x: 1 - kSpireMinW, y: kSpireMinH },
  892. { x: 1 - kSpireMinW, y: kSpireMaxH },
  893. { x: kSpireMinW, y: kSpireMaxH },
  894. // left quad
  895. { x: kSpireMinH, y: kSpireMinW },
  896. { x: kSpireMaxH, y: kSpireMinW },
  897. { x: kSpireMaxH, y: 1 - kSpireMinW },
  898. { x: kSpireMinH, y: 1 - kSpireMinW },
  899. ];
  900. // call KNWebGLBuildShimmerSystem initialize method
  901. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture, direction);
  902. this.setupWithTexture();
  903. },
  904. setupWithTexture: function() {
  905. this.animationWillBeginWithContext();
  906. // update vertex data
  907. this.p_setupVertexData();
  908. },
  909. p_setupVertexData: function() {
  910. var texRect = CGRectMake(0, 0, 1, 1);
  911. var numVertsPP = this.numberOfVerticesPerParticle;
  912. var oldParticleCount = this.particleCount;
  913. var newParticleCount = this.particleCount * 5;
  914. // objtain a reference of current data buffer
  915. var oldAttributeBuffers = this.attributeBuffers;
  916. // Set up fresh, new data buffer attributes!
  917. var newAttributeBuffers = {};
  918. newAttributeBuffers["Position"] = [];
  919. newAttributeBuffers["Center"] = [];
  920. newAttributeBuffers["TexCoord"] = [];
  921. newAttributeBuffers["ParticleTexCoord"] = [];
  922. newAttributeBuffers["Speed"] = [];
  923. newAttributeBuffers["Rotation"] = [];
  924. newAttributeBuffers["Scale"] = [];
  925. newAttributeBuffers["LifeSpan"] = [];
  926. newAttributeBuffers["Color"] = [];
  927. // Update new buffer with old buffer values
  928. for (var i = 0; i < oldParticleCount; ++i) {
  929. var oldVertIndex = i * 4;
  930. var thisScale = this.attributeBuffers["Scale"][oldVertIndex];
  931. var thisSpeed = WebGraphics.makePoint3D(
  932. this.attributeBuffers["Speed"][oldVertIndex * 3],
  933. this.attributeBuffers["Speed"][oldVertIndex * 3 + 1],
  934. this.attributeBuffers["Speed"][oldVertIndex * 3 + 2]
  935. );
  936. var thisColor = WebGraphics.makePoint4D(
  937. this.attributeBuffers["Color"][oldVertIndex * 4],
  938. this.attributeBuffers["Color"][oldVertIndex * 4 + 1],
  939. this.attributeBuffers["Color"][oldVertIndex * 4 + 2],
  940. this.attributeBuffers["Color"][oldVertIndex * 4 + 3]
  941. );
  942. var vertMin = WebGraphics.makePoint(
  943. this.attributeBuffers["Position"][oldVertIndex * 2],
  944. this.attributeBuffers["Position"][oldVertIndex * 2 + 1]
  945. );
  946. var vertMax = WebGraphics.makePoint(
  947. this.attributeBuffers["Position"][oldVertIndex * 2 + 4],
  948. this.attributeBuffers["Position"][oldVertIndex * 2 + 5]
  949. );
  950. var vertRect = TSDRectWithPoints(vertMin, vertMax);
  951. // set vertRect to empty if the particle from the object system is not visible
  952. if (this.objectSystem.particleSystemVisibilities[i] === false) {
  953. vertRect = TSDRectWithPoints(WebGraphics.makePoint(0, 0), WebGraphics.makePoint(0, 0));
  954. }
  955. var center = WebGraphics.makePoint(
  956. this.attributeBuffers["Center"][oldVertIndex * 2],
  957. this.attributeBuffers["Center"][oldVertIndex * 2 + 1]
  958. );
  959. var lifeSpan = WebGraphics.makePoint(
  960. this.attributeBuffers["LifeSpan"][oldVertIndex * 2],
  961. this.attributeBuffers["LifeSpan"][oldVertIndex * 2 + 1]
  962. );
  963. var p_particleHullArray = this.p_particleHullArray;
  964. var kNumHullPoints = this.kNumHullPoints;
  965. for (var v = 0; v < kNumHullPoints; ++v) {
  966. var newVertIndex = i * kNumHullPoints + v;
  967. var thisHullPoint = p_particleHullArray[v];
  968. var newVertexPoint = this.p_hullPoint(thisHullPoint, vertRect);
  969. KNWebGLUtil.setPoint2DAtIndexForAttribute(newVertexPoint, newVertIndex, newAttributeBuffers["Position"]);
  970. var newTexCoord = this.p_hullPoint(thisHullPoint, texRect);
  971. KNWebGLUtil.setPoint2DAtIndexForAttribute(newTexCoord, newVertIndex, newAttributeBuffers["ParticleTexCoord"]);
  972. KNWebGLUtil.setPoint2DAtIndexForAttribute(center, newVertIndex, newAttributeBuffers["Center"]);
  973. KNWebGLUtil.setPoint4DAtIndexForAttribute(thisColor, newVertIndex, newAttributeBuffers["Color"]);
  974. KNWebGLUtil.setPoint3DAtIndexForAttribute(thisSpeed, newVertIndex, newAttributeBuffers["Speed"]);
  975. KNWebGLUtil.setFloatAtIndexForAttribute(thisScale, newVertIndex, newAttributeBuffers["Scale"]);
  976. KNWebGLUtil.setPoint2DAtIndexForAttribute(lifeSpan, newVertIndex, newAttributeBuffers["LifeSpan"]);
  977. }
  978. }
  979. // update data buffer with new data buffer
  980. this.attributeBuffers = newAttributeBuffers;
  981. // update element array
  982. var elementArray = this.elementArray = [];
  983. var indexCounter = 0;
  984. for (var i = 0; i < newParticleCount; i++) {
  985. elementArray[indexCounter++] = 4 * i + 0;
  986. elementArray[indexCounter++] = 4 * i + 1;
  987. elementArray[indexCounter++] = 4 * i + 2;
  988. // second triangle
  989. elementArray[indexCounter++] = 4 * i + 0;
  990. elementArray[indexCounter++] = 4 * i + 2;
  991. elementArray[indexCounter++] = 4 * i + 3;
  992. }
  993. },
  994. p_hullPoint: function(hullPoint, vertexRect) {
  995. var point = WebGraphics.makePoint(vertexRect.origin.x + vertexRect.size.width * hullPoint.x, vertexRect.origin.y + vertexRect.size.height * hullPoint.y);
  996. return point;
  997. },
  998. startingPointAtIndexPoint: function(indexPoint) {
  999. var index = this.indexFromPoint(indexPoint) * 4;
  1000. var objectSystemVertexCount = this.objectSystemVertexCount;
  1001. var attributeBuffers = this.objectSystem.attributeBuffers["Position"];
  1002. if (index < objectSystemVertexCount) {
  1003. // Copy value from object particle system so this sparkle exactly matches up with an existing object particle
  1004. var result = WebGraphics.makePoint(
  1005. attributeBuffers[index * 2],
  1006. attributeBuffers[index * 2 + 1]
  1007. );
  1008. return result;
  1009. }
  1010. // else, it's an extra sparkle at the end, in a random location!
  1011. var halfWidth = this.objectSize.width / 2;
  1012. var halfHeight = this.objectSize.height / 2;
  1013. var midPoint = CGPointMake(halfWidth, halfHeight);
  1014. // attenuate points towards the middle
  1015. var r = WebGraphics.randomBetween(0, 1);
  1016. var angle = WebGraphics.doubleBetween(0, 2.0 * Math.PI);
  1017. var randLoc = CGPointMake(midPoint.x + halfWidth * r * Math.cos(angle), midPoint.y + halfHeight * r * Math.sin(angle));
  1018. return randLoc;
  1019. },
  1020. speedAtIndexPoint: function(indexPoint) {
  1021. var index = this.indexFromPoint(indexPoint) * 4;
  1022. var objectSystemVertexCount = this.objectSystemVertexCount;
  1023. var attributeBuffers = this.objectSystem.attributeBuffers["Speed"];
  1024. if (index < objectSystemVertexCount) {
  1025. // Copy value from object particle system so this sparkle exactly matches up with an existing object particle
  1026. var result = WebGraphics.makePoint3D(
  1027. attributeBuffers[index * 3],
  1028. attributeBuffers[index * 3 + 1],
  1029. attributeBuffers[index * 3 + 2]
  1030. );
  1031. return result;
  1032. }
  1033. // else, it's an extra sparkle at the end; stay in place
  1034. var speed = WebGraphics.makePoint3D(0, 0, 0);
  1035. return speed;
  1036. },
  1037. scaleAtIndexPoint: function(indexPoint) {
  1038. var minScale = 1.0;
  1039. var maxScale = 25.0;
  1040. var randNum = WebGraphics.randomBetween(0, 1);
  1041. // Most particles will be smaller
  1042. var result = TSUMix(minScale, maxScale, randNum * randNum);
  1043. return result;
  1044. },
  1045. lifeSpanAtIndexPoint: function(indexPoint) {
  1046. var index = this.indexFromPoint(indexPoint) * 4;
  1047. var objectSystemVertexCount = this.objectSystemVertexCount;
  1048. if (index < objectSystemVertexCount) {
  1049. // This is an existing object
  1050. return WebGraphics.makePoint(0, 1);
  1051. }
  1052. // else, it's an extra sparkle at the end, with a random life span!
  1053. // 2 second or 90% of total duration, whichever is shorter
  1054. var lifeDuration = Math.min(2.0 / (this.duration / 1000), 0.9);
  1055. var lifeStart = TSDMixFloats(0.01, 0.99, 1.0 - TSUReverseSquare(WebGraphics.randomBetween(0, 1)));
  1056. // Since percent is non-uniform, make duration less at later part of anim
  1057. lifeDuration *= TSUReverseSquare(lifeStart);
  1058. // Make sure lifespan ends before animation completes
  1059. lifeStart = Math.min(lifeStart, 0.99 - lifeDuration);
  1060. var result = WebGraphics.makePoint(lifeStart, lifeDuration);
  1061. return result;
  1062. },
  1063. colorAtIndexPoint: function(indexPoint) {
  1064. var index = this.indexFromPoint(indexPoint) * 4;
  1065. var objectSystemVertexCount = this.objectSystemVertexCount;
  1066. var attributeBuffers = this.objectSystem.attributeBuffers["Color"];
  1067. if (index < objectSystemVertexCount) {
  1068. // Copy value from object particle system so this sparkle exactly matches up with an existing object particle
  1069. var result = WebGraphics.makePoint4D(
  1070. attributeBuffers[index * 4],
  1071. attributeBuffers[index * 4 + 1],
  1072. attributeBuffers[index * 4 + 2],
  1073. attributeBuffers[index * 4 + 3]
  1074. );
  1075. return result;
  1076. }
  1077. // else it's an extra sparkle at the end
  1078. // white
  1079. var result = WebGraphics.makePoint4D(1, 1, 1, 1);
  1080. return result;
  1081. },
  1082. drawGLSLWithPercent: function(percent, opacity, rotation, clockwise) {
  1083. // Rotation Matrix
  1084. var angle = percent * (clockwise ? 1 : -1) * 2;
  1085. var rotMatrix = CGAffineTransformMakeRotation(angle);
  1086. var mat3 = WebGraphics.makeMat3WithAffineTransform(rotMatrix);
  1087. // set mat3 uniform for RotationMatrix
  1088. this.gl.uniformMatrix3fv(this.uniforms[kShimmerUniformRotationMatrix], false, mat3);
  1089. // Particle Scale Percent
  1090. var invPercent = 1.0 - percent;
  1091. var powPercent = Math.pow(invPercent, 15.0);
  1092. var particleScalePercent = TSUMix(invPercent * invPercent, 25. * percent, powPercent);
  1093. this.gl.uniform1f(this.uniforms[kShimmerUniformParticleScalePercent], particleScalePercent);
  1094. // Draw object
  1095. this.drawFrame(percent, opacity);
  1096. }
  1097. });
  1098. var KNWebGLBuildSparkleSystem = Class.create(KNWebGLParticleSystem, {
  1099. initialize: function($super, renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture, direction) {
  1100. this.willOverrideStartingPoints = true;
  1101. // number of vertices per particle
  1102. this.numberOfVerticesPerParticle = 4;
  1103. // set direction
  1104. this.direction = direction;
  1105. $super(renderer, program, objectSize, slideSize, duration, particleSystemSize, particleSize, texture);
  1106. // cache p_globalScale for faster access
  1107. this.cachedGlobalScale = this.p_globalScale();
  1108. this.setupWithTexture();
  1109. },
  1110. setupWithTexture: function() {
  1111. this.animationWillBeginWithContext();
  1112. },
  1113. p_globalScale: function() {
  1114. var objectSize = this.objectSize;
  1115. var slideSize = this.slideSize;
  1116. var minSide = Math.min(objectSize.width, objectSize.height);
  1117. var minSideRatio = minSide / (Math.min(slideSize.width, slideSize.height));
  1118. minSide = minSide / Math.sqrt(Math.sqrt(minSideRatio)) * 0.25;
  1119. return minSide;
  1120. },
  1121. startingPointAtIndexPoint: function(indexPoint) {
  1122. // CONSTANTS
  1123. var maxOffset = 0.1 / (this.duration / 1000);
  1124. var yAxis = (this.direction == KNDirection.kKNDirectionTopToBottom || this.direction == KNDirection.kKNDirectionBottomToTop);
  1125. var reverse = (this.direction == KNDirection.kKNDirectionRightToLeft || this.direction == KNDirection.kKNDirectionTopToBottom);
  1126. var index = this.indexFromPoint(indexPoint);
  1127. var x = index / this.particleCount; // position along line
  1128. x = reverse ? 1 - x : x;
  1129. var axis1 = x + maxOffset * WebGraphics.doubleBetween(-1.0, 1.0);
  1130. var axis2 = Math.random();
  1131. // skew position towards center vertically
  1132. axis2 = 2. * axis2 - 1.;
  1133. axis2 *= Math.abs(axis2);
  1134. axis2 = (axis2 + 1.) / 2.;
  1135. var newX = yAxis ? axis2 : axis1;
  1136. var newY = yAxis ? axis1 : axis2;
  1137. var position = WebGraphics.makePoint(
  1138. newX * this.objectSize.width - this.particleSize.width / 2.0,
  1139. newY * this.objectSize.height - this.particleSize.height / 2.0
  1140. );
  1141. return position;
  1142. },
  1143. speedAtIndexPoint: function(point) {
  1144. var speed = this.point3DRandomDirection();
  1145. // reduce z speed
  1146. speed.z *= 0.01;
  1147. var randomMultiplier = Math.random();
  1148. var result = WebGraphics.multiplyPoint3DByScalar(speed, randomMultiplier);
  1149. return result;
  1150. },
  1151. speedMax: function() {
  1152. var minSide = Math.min(this.objectSize.width, this.objectSize.height);
  1153. var minSideRatio = minSide / (Math.min(this.slideSize.width, this.slideSize.height));
  1154. minSide = minSide / Math.pow(minSideRatio, 0.667) * 0.25 * 1.5;
  1155. return minSide;
  1156. },
  1157. scaleAtIndexPoint: function(indexPoint) {
  1158. var minSide = this.cachedGlobalScale;
  1159. var result = minSide / this.particleSize.width;
  1160. return result;
  1161. },
  1162. lifeSpanAtIndexPoint: function(indexPoint) {
  1163. var index = this.indexFromPoint(indexPoint);
  1164. var timeStart = index / this.particleCount;
  1165. var timeDuration = KNSparkleMaxParticleLife / Math.max(0.75, this.duration/1000);
  1166. timeStart *= 1 - timeDuration;
  1167. var lifeSpan = WebGraphics.makePoint(timeStart, timeDuration);
  1168. return lifeSpan;
  1169. }
  1170. });