You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

KNWebGLWrapper.js 14KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * KNWebGLWrapper.js
  3. * Keynote HTML Player
  4. *
  5. * Created by Tungwei Cheng
  6. * Copyright (c) 2019 Apple Inc. All rights reserved.
  7. */
  8. var KNWebGLCoreAnimationWrapperProjectionTransformType = {
  9. Invalid: 0,
  10. Orthographic: 1,
  11. Perspective: 2,
  12. Custom: 3
  13. };
  14. var KNWebGLCoreAnimationWrapperTextureDrawOptions = Class.create({
  15. initialize: function(textureInfo, effectDuration, baseTransform) {
  16. // is hidden
  17. this.hidden = false;
  18. // culling backface
  19. this.wantsBackFaceCulling = false;
  20. // is background texture
  21. this.isBackground = false;
  22. // is foreground texture
  23. this.isForeground = true;
  24. // if this object isn't moving at all, we can optimize around that
  25. this.isMoving = true;
  26. // is blending between two textures
  27. this.isBlending = false;
  28. // texture opacity from animation
  29. this.opacity = 1;
  30. // all things related to the texture
  31. this.textureInfo = textureInfo;
  32. // duration of current effect in seconds
  33. this.effectDuration = effectDuration;
  34. // base transform matrix for the object
  35. this.baseTransform = baseTransform;
  36. }
  37. });
  38. var KNWebGLCoreAnimationWrapperProgram = Class.create({
  39. initialize: function(params) {
  40. this.name = "CoreAnimationWrapperBasedEffect";
  41. this.effect = params.effect;
  42. this.textures = params.textures;
  43. this.data = {
  44. name: this.name,
  45. programNames: [],
  46. effect: this.effect,
  47. textures: this.textures
  48. };
  49. }
  50. });
  51. var KNWebGLCoreAnimationWrapper = Class.create({
  52. initialize: function(gl) {
  53. // initialize wrapper class to be used in core animation wrapper based effects
  54. this.gl = gl;
  55. this.setupWithContext();
  56. },
  57. setupWithContext: function() {
  58. // setup animation parameter group for timing function
  59. this.animParameterGroup = new KNAnimParameterGroup("timingFunction");
  60. },
  61. renderFrameWithContext: function(objectShader, objectDataBuffer, textureDrawOptions) {
  62. var gl = this.gl;
  63. var parameterGroup = this.animParameterGroup;
  64. // texture draw options
  65. var textureInfo = textureDrawOptions.textureInfo;
  66. var textureRect = textureInfo.textureRect;
  67. var initialState = textureInfo.initialState;
  68. // overall duration for the effect
  69. var overallDuration = textureDrawOptions.effectDuration;
  70. // base transform matrix for the object
  71. var baseTransform = textureDrawOptions.baseTransform;
  72. // effect percent
  73. var percent = textureDrawOptions.percent;
  74. // is the effect blending two textures
  75. var isBlending = textureDrawOptions.isBlending;
  76. // default transfrom origin
  77. var transformPoint = {
  78. x: textureRect.size.width / 2,
  79. y: textureRect.size.height / 2
  80. };
  81. // postion
  82. var fromPositionX = 0;
  83. var fromPositionY = 0;
  84. var toPositionX = 0;
  85. var toPositionY = 0;
  86. var offsetX = 0;
  87. var offsetY = 0;
  88. // scale
  89. var fromScaleX = 1;
  90. var fromScaleY = 1;
  91. var toScaleX = 1;
  92. var toScaleY = 1;
  93. // rotate
  94. var hasRotationZ = false;
  95. var fromRotationZ = 0;
  96. var toRotationZ = 0;
  97. // opacity
  98. var fromOpacity = 1;
  99. var toOpacity = 1;
  100. var opacityPercent = 0;
  101. // contents
  102. var outgoingTexture = textureInfo.texture;
  103. var incomingTexture;
  104. // search the animations within group
  105. var groupAnimations = textureInfo.animations;
  106. var animations = groupAnimations[0].animations;
  107. for (var i = 0, length = animations.length; i < length; i++) {
  108. var animation = animations[i];
  109. var key = animation.property;
  110. var fromValue = animation.from;
  111. var toValue = animation.to;
  112. var newPercent = percent;
  113. var beginTime = animation.beginTime * 1000;
  114. var duration = animation.duration * 1000;
  115. // apply timing function for the animation curve if it is not linear
  116. if (animation.timingFunction && animation.timingFunction !== "Linear") {
  117. newPercent = parameterGroup.doubleForAnimationCurve(animation.timingFunction, percent);
  118. }
  119. switch (key) {
  120. case "transform.translation":
  121. fromPositionX = fromValue.pointX;
  122. fromPositionY = fromValue.pointY;
  123. toPositionX = toValue.pointX;
  124. toPositionY = toValue.pointY;
  125. offsetX = (toValue.pointX - fromValue.pointX) * newPercent;
  126. offsetY = (toValue.pointY - fromValue.pointY) * newPercent;
  127. break;
  128. case "transform.rotation.z":
  129. hasRotationZ = true;
  130. fromRotationZ = fromValue.scalar;
  131. toRotationZ = toValue.scalar;
  132. break;
  133. case "transform.scale.x":
  134. fromScaleX = fromValue.scalar;
  135. toScaleX = toValue.scalar;
  136. break;
  137. case "transform.scale.y":
  138. fromScaleY = fromValue.scalar;
  139. toScaleY = toValue.scalar;
  140. break;
  141. case "opacity":
  142. fromOpacity = fromValue.scalar;
  143. toOpacity = toValue.scalar;
  144. if (overallDuration !== duration) {
  145. var timeAtPercent = percent * overallDuration;
  146. if (timeAtPercent < beginTime) {
  147. opacityPercent = 0;
  148. } else if (timeAtPercent > beginTime + duration) {
  149. opacityPercent = 1;
  150. } else {
  151. opacityPercent = (timeAtPercent - beginTime) / duration;
  152. }
  153. if (animation.timingFunction && animation.timingFunction !== "Linear") {
  154. opacityPercent = parameterGroup.doubleForAnimationCurve(animation.timingFunction, opacityPercent);
  155. }
  156. } else {
  157. opacityPercent = newPercent;
  158. }
  159. break;
  160. case "contents":
  161. incomingTexture = textureInfo.toTexture;
  162. break;
  163. default:
  164. break;
  165. }
  166. }
  167. // Opacity animation
  168. var opacity = initialState.hidden ? 0 : textureInfo.parentOpacity * initialState.opacity;
  169. if (fromOpacity !== toOpacity) {
  170. opacity = fromOpacity + (toOpacity - fromOpacity) * opacityPercent;
  171. }
  172. objectShader.setGLFloat(opacity, kTSDGLShaderUniformOpacity);
  173. var mvpMatrix = WebGraphics.translateMatrix4(baseTransform, fromPositionX, -fromPositionY, 0);
  174. // Affine Transform Translation
  175. mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, offsetX, -offsetY, 0);
  176. // Affine Transform Rotation and Scale
  177. // set transform origin by translating to the transform center
  178. // find out if the anchorPoint is different from the default and apply the offset
  179. var anchorPoint = initialState.anchorPoint;
  180. if (anchorPoint.pointX !== 0.5 || anchorPoint.pointY !== 0.5) {
  181. // set the new transform point
  182. transformPoint.x = anchorPoint.pointX * textureRect.size.width;
  183. transformPoint.y = (1 - anchorPoint.pointY) * textureRect.size.height;
  184. }
  185. mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, transformPoint.x, transformPoint.y, 0);
  186. // set rotation amount to initial state rotation
  187. var rotatedRadian = initialState.rotation;
  188. if (hasRotationZ) {
  189. // if the from value is different from initial state then use the from value
  190. if (fromRotationZ !== rotatedRadian) {
  191. rotatedRadian = fromRotationZ;
  192. }
  193. // add up the rotatedRadian for each percentage update
  194. rotatedRadian = rotatedRadian + (toRotationZ - fromRotationZ) * newPercent;
  195. }
  196. // apply the rotation
  197. if (rotatedRadian !== 0) {
  198. mvpMatrix = WebGraphics.rotateMatrix4AboutXYZ(mvpMatrix, -rotatedRadian, 0, 0, 1);
  199. }
  200. // apply initial state scale
  201. var initialStateScale = initialState.scale;
  202. if (initialStateScale !== 1) {
  203. mvpMatrix = WebGraphics.scaleMatrix4(mvpMatrix, initialStateScale, initialStateScale, 1);
  204. }
  205. // apply transform Scale if there is scale animation
  206. if (fromScaleX !== toScaleX || fromScaleY !== toScaleY) {
  207. mvpMatrix = WebGraphics.scaleMatrix4(mvpMatrix, (toScaleX - fromScaleX) * newPercent + fromScaleX, (toScaleY - fromScaleY) * newPercent + fromScaleY, 1);
  208. }
  209. // untranslate the translation to the transform center
  210. mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, -transformPoint.x, -transformPoint.y, 0);
  211. objectShader.setMat4WithTransform3D(mvpMatrix, kTSDGLShaderUniformMVPMatrix);
  212. // set up default blend mode
  213. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  214. // if there is an incoming texture then it is contents animations
  215. if (isBlending) {
  216. gl.activeTexture(gl.TEXTURE1);
  217. gl.bindTexture(gl.TEXTURE_2D, incomingTexture);
  218. gl.activeTexture(gl.TEXTURE0);
  219. gl.bindTexture(gl.TEXTURE_2D, outgoingTexture);
  220. objectShader.setGLFloat(newPercent, "mixFactor");
  221. } else {
  222. gl.bindTexture(gl.TEXTURE_2D, outgoingTexture);
  223. }
  224. objectDataBuffer.drawWithShader(objectShader, true);
  225. }
  226. });
  227. var KNWebGLCoreAnimationWrapperBasedEffect = Class.create({
  228. initialize: function(renderer, program, slideRect, texture, frameRect, baseTransform, duration, direction, buildType, parentOpacity) {
  229. this.renderer = renderer;
  230. this.gl = renderer.gl;
  231. this.program = program;
  232. this.slideRect = slideRect;
  233. this.texture = texture;
  234. this.frameRect = frameRect;
  235. this.baseTransform = baseTransform;
  236. this.duration = duration;
  237. this.direction = direction;
  238. this.buildType = buildType;
  239. this.parentOpacity = parentOpacity;
  240. // animation parameter group
  241. this.animParameterGroup = new KNAnimParameterGroup("timingFunction");
  242. this.percentfinished = 0;
  243. this.prepareAnimationWithContext();
  244. this.animationWillBeginWithContext();
  245. },
  246. isOrthographicProjection: function() {
  247. return true;
  248. },
  249. prepareAnimationWithContext: function() {
  250. // prepare core animation wrapper from the gl renderer
  251. this.coreAnimationWrapper = this.renderer.coreAnimationWrapper;
  252. // default texture draw options
  253. var textureDrawOptions = this.textureDrawOptions = new KNWebGLCoreAnimationWrapperTextureDrawOptions(this.texture, this.duration, this.baseTransform);
  254. // is blending between two textures
  255. textureDrawOptions.isBlending = this.texture.toTexture ? true : false;
  256. },
  257. animationWillBeginWithContext: function() {
  258. var renderer = this.renderer;
  259. var gl = this.gl;
  260. var frameRect = this.frameRect;
  261. var meshSize = CGSizeMake(2, 2);
  262. var texture = this.texture;
  263. // init object shader and data buffer
  264. var objectShader = this.objectShader = new TSDGLShader(gl);
  265. objectShader.initWithContentsAndOpacityShader();
  266. // object shader set methods
  267. objectShader.setMat4WithTransform3D(this.baseTransform, kTSDGLShaderUniformMVPMatrix);
  268. // outgoing texture
  269. objectShader.setGLint(0, kTSDGLShaderUniformTexture2);
  270. // incoming Texture
  271. objectShader.setGLint(1, kTSDGLShaderUniformTexture);
  272. // init object data buffer
  273. var objectTextureRect = this.texture.textureRect;
  274. var objectVertexRect = CGRectMake(0, 0, objectTextureRect.size.width, objectTextureRect.size.height);
  275. var objectDataBuffer = this.objectDataBuffer = new TSDGLDataBuffer(gl);
  276. objectDataBuffer.initWithVertexRect(objectVertexRect, TSDRectUnit, meshSize, false, false);
  277. },
  278. drawFrame: function(difference, elapsed, duration) {
  279. var renderer = this.renderer;
  280. var gl = this.gl;
  281. var buildOut = this.buildOut;
  282. var percentfinished = this.percentfinished;
  283. percentfinished += difference / duration;
  284. if (percentfinished >= 1) {
  285. percentfinished = 1;
  286. this.isCompleted = true;
  287. }
  288. this.percentfinished = percentfinished;
  289. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  290. var textureInfo = this.texture;
  291. var initialState = textureInfo.initialState;
  292. var animations = textureInfo.animations;
  293. var objectShader = this.objectShader;
  294. var objectDataBuffer = this.objectDataBuffer;
  295. if (textureInfo.animations.length > 0) {
  296. var percent = percentfinished;
  297. // update texture draw options
  298. var textureDrawOptions = this.textureDrawOptions;
  299. textureDrawOptions.percent = percent;
  300. // render the effect in core animation wrapper
  301. this.coreAnimationWrapper.renderFrameWithContext(objectShader, objectDataBuffer, textureDrawOptions);
  302. } else {
  303. var opacity = textureInfo.initialState.hidden ? 0 : this.parentOpacity * textureInfo.initialState.opacity;
  304. // set texture opacity
  305. objectShader.setGLFloat(opacity, kTSDGLShaderUniformOpacity);
  306. // draw static object
  307. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  308. gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture);
  309. objectDataBuffer.drawWithShader(objectShader, true);
  310. }
  311. }
  312. });