|
- /*
- * KNWebGLWrapper.js
- * Keynote HTML Player
- *
- * Created by Tungwei Cheng
- * Copyright (c) 2019 Apple Inc. All rights reserved.
- */
-
- var KNWebGLCoreAnimationWrapperProjectionTransformType = {
- Invalid: 0,
- Orthographic: 1,
- Perspective: 2,
- Custom: 3
- };
-
- var KNWebGLCoreAnimationWrapperTextureDrawOptions = Class.create({
- initialize: function(textureInfo, effectDuration, baseTransform) {
- // is hidden
- this.hidden = false;
-
- // culling backface
- this.wantsBackFaceCulling = false;
-
- // is background texture
- this.isBackground = false;
-
- // is foreground texture
- this.isForeground = true;
-
- // if this object isn't moving at all, we can optimize around that
- this.isMoving = true;
-
- // is blending between two textures
- this.isBlending = false;
-
- // texture opacity from animation
- this.opacity = 1;
-
- // all things related to the texture
- this.textureInfo = textureInfo;
-
- // duration of current effect in seconds
- this.effectDuration = effectDuration;
-
- // base transform matrix for the object
- this.baseTransform = baseTransform;
- }
- });
-
- var KNWebGLCoreAnimationWrapperProgram = Class.create({
- initialize: function(params) {
- this.name = "CoreAnimationWrapperBasedEffect";
- this.effect = params.effect;
- this.textures = params.textures;
-
- this.data = {
- name: this.name,
- programNames: [],
- effect: this.effect,
- textures: this.textures
- };
- }
- });
-
- var KNWebGLCoreAnimationWrapper = Class.create({
- initialize: function(gl) {
- // initialize wrapper class to be used in core animation wrapper based effects
- this.gl = gl;
-
- this.setupWithContext();
- },
-
- setupWithContext: function() {
- // setup animation parameter group for timing function
- this.animParameterGroup = new KNAnimParameterGroup("timingFunction");
- },
-
- renderFrameWithContext: function(objectShader, objectDataBuffer, textureDrawOptions) {
- var gl = this.gl;
-
- var parameterGroup = this.animParameterGroup;
-
- // texture draw options
- var textureInfo = textureDrawOptions.textureInfo;
- var textureRect = textureInfo.textureRect;
- var initialState = textureInfo.initialState;
-
- // overall duration for the effect
- var overallDuration = textureDrawOptions.effectDuration;
-
- // base transform matrix for the object
- var baseTransform = textureDrawOptions.baseTransform;
-
- // effect percent
- var percent = textureDrawOptions.percent;
-
- // is the effect blending two textures
- var isBlending = textureDrawOptions.isBlending;
-
- // default transfrom origin
- var transformPoint = {
- x: textureRect.size.width / 2,
- y: textureRect.size.height / 2
- };
-
- // postion
- var fromPositionX = 0;
- var fromPositionY = 0;
- var toPositionX = 0;
- var toPositionY = 0;
- var offsetX = 0;
- var offsetY = 0;
-
- // scale
- var fromScaleX = 1;
- var fromScaleY = 1;
- var toScaleX = 1;
- var toScaleY = 1;
-
- // rotate
- var hasRotationZ = false;
- var fromRotationZ = 0;
- var toRotationZ = 0;
-
- // opacity
- var fromOpacity = 1;
- var toOpacity = 1;
- var opacityPercent = 0;
-
- // contents
- var outgoingTexture = textureInfo.texture;
- var incomingTexture;
-
- // search the animations within group
- var groupAnimations = textureInfo.animations;
- var animations = groupAnimations[0].animations;
-
- for (var i = 0, length = animations.length; i < length; i++) {
- var animation = animations[i];
- var key = animation.property;
- var fromValue = animation.from;
- var toValue = animation.to;
- var newPercent = percent;
- var beginTime = animation.beginTime * 1000;
- var duration = animation.duration * 1000;
-
- // apply timing function for the animation curve if it is not linear
- if (animation.timingFunction && animation.timingFunction !== "Linear") {
- newPercent = parameterGroup.doubleForAnimationCurve(animation.timingFunction, percent);
- }
-
- switch (key) {
- case "transform.translation":
- fromPositionX = fromValue.pointX;
- fromPositionY = fromValue.pointY;
- toPositionX = toValue.pointX;
- toPositionY = toValue.pointY;
- offsetX = (toValue.pointX - fromValue.pointX) * newPercent;
- offsetY = (toValue.pointY - fromValue.pointY) * newPercent;
- break;
-
- case "transform.rotation.z":
- hasRotationZ = true;
- fromRotationZ = fromValue.scalar;
- toRotationZ = toValue.scalar;
- break;
-
- case "transform.scale.x":
- fromScaleX = fromValue.scalar;
- toScaleX = toValue.scalar;
- break;
-
- case "transform.scale.y":
- fromScaleY = fromValue.scalar;
- toScaleY = toValue.scalar;
- break;
-
- case "opacity":
- fromOpacity = fromValue.scalar;
- toOpacity = toValue.scalar;
-
- if (overallDuration !== duration) {
- var timeAtPercent = percent * overallDuration;
-
- if (timeAtPercent < beginTime) {
- opacityPercent = 0;
- } else if (timeAtPercent > beginTime + duration) {
- opacityPercent = 1;
- } else {
- opacityPercent = (timeAtPercent - beginTime) / duration;
- }
-
- if (animation.timingFunction && animation.timingFunction !== "Linear") {
- opacityPercent = parameterGroup.doubleForAnimationCurve(animation.timingFunction, opacityPercent);
- }
- } else {
- opacityPercent = newPercent;
- }
- break;
-
- case "contents":
- incomingTexture = textureInfo.toTexture;
- break;
-
- default:
- break;
- }
- }
-
- // Opacity animation
- var opacity = initialState.hidden ? 0 : textureInfo.parentOpacity * initialState.opacity;
-
- if (fromOpacity !== toOpacity) {
- opacity = fromOpacity + (toOpacity - fromOpacity) * opacityPercent;
- }
-
- objectShader.setGLFloat(opacity, kTSDGLShaderUniformOpacity);
-
- var mvpMatrix = WebGraphics.translateMatrix4(baseTransform, fromPositionX, -fromPositionY, 0);
-
- // Affine Transform Translation
- mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, offsetX, -offsetY, 0);
-
- // Affine Transform Rotation and Scale
-
- // set transform origin by translating to the transform center
- // find out if the anchorPoint is different from the default and apply the offset
- var anchorPoint = initialState.anchorPoint;
-
- if (anchorPoint.pointX !== 0.5 || anchorPoint.pointY !== 0.5) {
- // set the new transform point
- transformPoint.x = anchorPoint.pointX * textureRect.size.width;
- transformPoint.y = (1 - anchorPoint.pointY) * textureRect.size.height;
- }
-
- mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, transformPoint.x, transformPoint.y, 0);
-
- // set rotation amount to initial state rotation
- var rotatedRadian = initialState.rotation;
-
- if (hasRotationZ) {
- // if the from value is different from initial state then use the from value
- if (fromRotationZ !== rotatedRadian) {
- rotatedRadian = fromRotationZ;
- }
-
- // add up the rotatedRadian for each percentage update
- rotatedRadian = rotatedRadian + (toRotationZ - fromRotationZ) * newPercent;
- }
-
- // apply the rotation
- if (rotatedRadian !== 0) {
- mvpMatrix = WebGraphics.rotateMatrix4AboutXYZ(mvpMatrix, -rotatedRadian, 0, 0, 1);
- }
-
- // apply initial state scale
- var initialStateScale = initialState.scale;
- if (initialStateScale !== 1) {
- mvpMatrix = WebGraphics.scaleMatrix4(mvpMatrix, initialStateScale, initialStateScale, 1);
- }
-
- // apply transform Scale if there is scale animation
- if (fromScaleX !== toScaleX || fromScaleY !== toScaleY) {
- mvpMatrix = WebGraphics.scaleMatrix4(mvpMatrix, (toScaleX - fromScaleX) * newPercent + fromScaleX, (toScaleY - fromScaleY) * newPercent + fromScaleY, 1);
- }
-
- // untranslate the translation to the transform center
- mvpMatrix = WebGraphics.translateMatrix4(mvpMatrix, -transformPoint.x, -transformPoint.y, 0);
-
- objectShader.setMat4WithTransform3D(mvpMatrix, kTSDGLShaderUniformMVPMatrix);
-
- // set up default blend mode
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
-
- // if there is an incoming texture then it is contents animations
- if (isBlending) {
- gl.activeTexture(gl.TEXTURE1);
- gl.bindTexture(gl.TEXTURE_2D, incomingTexture);
-
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, outgoingTexture);
-
- objectShader.setGLFloat(newPercent, "mixFactor");
- } else {
- gl.bindTexture(gl.TEXTURE_2D, outgoingTexture);
- }
-
- objectDataBuffer.drawWithShader(objectShader, true);
- }
- });
-
- var KNWebGLCoreAnimationWrapperBasedEffect = Class.create({
- initialize: function(renderer, program, slideRect, texture, frameRect, baseTransform, duration, direction, buildType, parentOpacity) {
- this.renderer = renderer;
- this.gl = renderer.gl;
-
- this.program = program;
- this.slideRect = slideRect;
- this.texture = texture;
- this.frameRect = frameRect;
- this.baseTransform = baseTransform;
- this.duration = duration;
- this.direction = direction;
- this.buildType = buildType;
- this.parentOpacity = parentOpacity;
-
- // animation parameter group
- this.animParameterGroup = new KNAnimParameterGroup("timingFunction");
-
- this.percentfinished = 0;
-
- this.prepareAnimationWithContext();
-
- this.animationWillBeginWithContext();
- },
-
- isOrthographicProjection: function() {
- return true;
- },
-
- prepareAnimationWithContext: function() {
- // prepare core animation wrapper from the gl renderer
- this.coreAnimationWrapper = this.renderer.coreAnimationWrapper;
-
- // default texture draw options
- var textureDrawOptions = this.textureDrawOptions = new KNWebGLCoreAnimationWrapperTextureDrawOptions(this.texture, this.duration, this.baseTransform);
-
- // is blending between two textures
- textureDrawOptions.isBlending = this.texture.toTexture ? true : false;
- },
-
- animationWillBeginWithContext: function() {
- var renderer = this.renderer;
- var gl = this.gl;
- var frameRect = this.frameRect;
- var meshSize = CGSizeMake(2, 2);
-
- var texture = this.texture;
-
- // init object shader and data buffer
- var objectShader = this.objectShader = new TSDGLShader(gl);
- objectShader.initWithContentsAndOpacityShader();
-
- // object shader set methods
- objectShader.setMat4WithTransform3D(this.baseTransform, kTSDGLShaderUniformMVPMatrix);
-
- // outgoing texture
- objectShader.setGLint(0, kTSDGLShaderUniformTexture2);
-
- // incoming Texture
- objectShader.setGLint(1, kTSDGLShaderUniformTexture);
-
- // init object data buffer
- var objectTextureRect = this.texture.textureRect;
- var objectVertexRect = CGRectMake(0, 0, objectTextureRect.size.width, objectTextureRect.size.height);
- var objectDataBuffer = this.objectDataBuffer = new TSDGLDataBuffer(gl);
-
- objectDataBuffer.initWithVertexRect(objectVertexRect, TSDRectUnit, meshSize, false, false);
- },
-
- drawFrame: function(difference, elapsed, duration) {
- var renderer = this.renderer;
- var gl = this.gl;
- var buildOut = this.buildOut;
- var percentfinished = this.percentfinished;
-
- percentfinished += difference / duration;
-
- if (percentfinished >= 1) {
- percentfinished = 1;
- this.isCompleted = true;
- }
-
- this.percentfinished = percentfinished;
-
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
-
- var textureInfo = this.texture;
- var initialState = textureInfo.initialState;
- var animations = textureInfo.animations;
-
- var objectShader = this.objectShader;
- var objectDataBuffer = this.objectDataBuffer;
-
- if (textureInfo.animations.length > 0) {
- var percent = percentfinished;
-
- // update texture draw options
- var textureDrawOptions = this.textureDrawOptions;
- textureDrawOptions.percent = percent;
-
- // render the effect in core animation wrapper
- this.coreAnimationWrapper.renderFrameWithContext(objectShader, objectDataBuffer, textureDrawOptions);
- } else {
- var opacity = textureInfo.initialState.hidden ? 0 : this.parentOpacity * textureInfo.initialState.opacity;
-
- // set texture opacity
- objectShader.setGLFloat(opacity, kTSDGLShaderUniformOpacity);
-
- // draw static object
- gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
- gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture);
- objectDataBuffer.drawWithShader(objectShader, true);
- }
- }
- });
|