blob: ac9f6e782a5ea75a5d4b83f39e6004c031b23684 [file] [log] [blame]
function WebGLRenderer(animationItem, config){
this.animationItem = animationItem;
this.renderConfig = {
clearCanvas: (config && config.clearCanvas !== undefined) ? config.clearCanvas : true,
context: (config && config.context) || null,
progressiveLoad: (config && config.progressiveLoad) || false,
preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet',
imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice',
className: (config && config.className) || ''
};
this.renderConfig.dpr = (config && config.dpr) || 1;
if (this.animationItem.wrapper) {
this.renderConfig.dpr = (config && config.dpr) || window.devicePixelRatio || 1;
}
this.renderedFrame = -1;
this.globalData = {
frameNum: -1,
_mdf: false,
renderConfig: this.renderConfig
};
this._stencilCount = 0;
this.elements = [];
this.pendingElements = [];
this.transformMat = new Matrix();
this.precompStack = [];
this.completeLayers = false;
this._root = true;
}
extendPrototype([BaseRenderer],WebGLRenderer);
WebGLRenderer.prototype.configAnimation = function(animData){
if(this.animationItem.wrapper){
this.animationItem.container = createTag('canvas');
this.animationItem.container.style.width = '100%';
this.animationItem.container.style.height = '100%';
//this.animationItem.container.style.transform = 'translate3d(0,0,0)';
//this.animationItem.container.style.webkitTransform = 'translate3d(0,0,0)';
this.animationItem.container.style.transformOrigin = this.animationItem.container.style.mozTransformOrigin = this.animationItem.container.style.webkitTransformOrigin = this.animationItem.container.style['-webkit-transform'] = "0px 0px 0px";
this.animationItem.wrapper.appendChild(this.animationItem.container);
var glc = this.animationItem.container.getContext('webgl');
// ////
var _debug = false;
if (_debug) {
this.glContext = new Proxy(glc, {
get(target, propKey, receiver) {
if (typeof target[propKey] === 'function') {
const origMethod = target[propKey];
return function (...args) {
const result = origMethod.apply(target, args);
console.log('==========')
console.log(propKey)
// args.forEach(arg => {
// console.log(arg)
// })
// console.log('==========')
// console.log(propKey + JSON.stringify(args)
// + ' -> ' + JSON.stringify(result));
return result;
};
} else {
console.log('GETTING: ', propKey)
return target[propKey]
}
}
})
} else {
this.glContext = glc
}
//
////
// Enabled blend and sets blend func to handle opacity.
//TODO: rename to glContext
this.glContext.enable(this.glContext.BLEND);
this.glContext.blendFunc(this.glContext.SRC_ALPHA, this.glContext.ONE_MINUS_SRC_ALPHA);
if(this.renderConfig.className) {
this.animationItem.container.setAttribute('class', this.renderConfig.className);
}
}else{
this.glContext = this.renderConfig.context;
}
this.transformCanvas = {
w: animData.w,
h:animData.h,
sx:0,
sy:0,
tx:0,
ty:0
};
this.data = animData;
this.layers = animData.layers;
this.setupGlobalData(animData, document.body);
this.globalData.glContext = this.glContext;
if (!this.camera) {
console.log('PASO 1')
this.camera = new WebGLCamera(null, this.globalData, this);
}
// Position buffer data
var glContext = this.glContext;
//General Array Buffer. Position buffer. Will be used by all layers.
this.positionBuffer = glContext.createBuffer();
glContext.bindBuffer(glContext.ARRAY_BUFFER, this.positionBuffer);
var positions = [
0, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
];
glContext.bufferData(glContext.ARRAY_BUFFER, new Float32Array(positions), glContext.STATIC_DRAW);
//
this.globalData.positionBuffer = this.positionBuffer;
this.globalData.renderer = this;
this.globalData.isDashed = false;
this.globalData.progressiveLoad = this.renderConfig.progressiveLoad;
this.globalData.resetViewport = this.resetViewport.bind(this);
this.globalData.globalBuffer = this.positionBuffer;
this.elements = createSizedArray(animData.layers.length);
this.updateContainerSize();
};
WebGLRenderer.prototype.getTransform = function() {
return this.transformMat;
}
WebGLRenderer.prototype.getTrackMatteElement = function(element) {
var i = 0, len = this.elements.length;
while (i < len) {
if(this.elements[i] === element) {
return this.elements[i - 1];
}
i += 1;
}
}
WebGLRenderer.prototype.buildItem = function(pos){
var elements = this.elements;
if(elements[pos] || this.layers[pos].ty == 99){
return;
}
var element = this.createItem(this.layers[pos], this,this.globalData);
elements[pos] = element;
element.initExpressions();
if(this.layers[pos].tt){
element.renderableEffectsManager.pushEffect(new WTrackMatte(element, elements[pos - 1]));
}
};
WebGLRenderer.prototype.calculateTransformSize = CanvasRenderer.prototype.calculateTransformSize;
WebGLRenderer.prototype.updateContainerSize = function() {
this.calculateTransformSize();
var scaleX = 1, scaleY = 1;
var elementWidth,elementHeight, elementRel;
elementWidth = this.glContext.canvas.width;
elementHeight = this.glContext.canvas.height;
elementRel = elementWidth / elementHeight;
var animationRel = this.transformCanvas.w / this.transformCanvas.h;
if(animationRel > elementRel) {
scaleY = (this.transformCanvas.h * this.transformCanvas.sy) / elementHeight;
} else {
scaleX = (this.transformCanvas.w * this.transformCanvas.sx) / elementWidth;
}
this.scaleX = scaleX;
this.scaleY = scaleY;
// this.transformMat.reset();
// this.transformMat.scale(scaleX, scaleY);
// this.transformMat.scale(1 / this.data.w, 1 / this.data.h, 1 / 1666);
// this.transformMat.scale(2, 2);
// this.transformMat.translate(-1, -1);
// this.transformMat.translate(1 - scaleX, 1 - scaleY);
// this.transformMat.scale(1, -1);
this.resetViewport();
};
WebGLRenderer.prototype.switchBuffer = function() {
// TODO: validate current buffer before switching to avoid unnecessary calls.
var glContext = this.glContext;
if (this._root) {
this.glContext.bindFramebuffer(glContext.FRAMEBUFFER, null);
this.resetViewport();
} else {
glContext.bindFramebuffer(glContext.FRAMEBUFFER, this.bufferData.framebuffer);
glContext.viewport(0, 0, this.data.w, this.data.h);
}
}
WebGLRenderer.prototype.resetViewport = function (data) {
this.glContext.viewport(0, 0, this.animationItem.container.width, this.animationItem.container.height);
};
WebGLRenderer.prototype.createImage = function (data) {
return new WImageElement(data, this.globalData, this);
};
WebGLRenderer.prototype.createSolid = function (data) {
return new WSolidElement(data, this.globalData, this);
};
WebGLRenderer.prototype.createComp = function (data) {
return new WCompElement(data, this.globalData, this);
};
WebGLRenderer.prototype.createNull = SVGRenderer.prototype.createNull;
WebGLRenderer.prototype.createShape = function (data) {
return new WShapeElement(data,this.globalData,this);
};
WebGLRenderer.prototype.createCamera = function (data) {
this.camera = new WebGLCamera(data, this.globalData, this);
return this.camera;
};
WebGLRenderer.prototype.checkPendingElements = function(){
while(this.pendingElements.length){
var element = this.pendingElements.pop();
element.checkParenting();
}
};
WebGLRenderer.prototype.getSize = function(){
return this.transformCanvas;
}
WebGLRenderer.prototype.applyCameraTransformation = function(){
this.transformMat.reset();
this.transformMat.scale(this.scaleX, this.scaleY);
var p = this.camera.mat.props;
console.log(p)
this.transformMat.transform(p[0], p[1], p[2], p[3]
,p[4], p[5], p[6], p[7]
,p[8], p[9], p[10], p[11]
,p[12], p[13], p[14], p[15]);
// convert values to range [0, 1]
this.transformMat.scale(1 / this.data.w, 1 / this.data.h, 1);
// convert values to range [0, 2]
this.transformMat.scale(2, 2);
// convert values to range [-1, 1]
this.transformMat.translate(-1, -1);
// convert values to fit inside actual canvas
this.transformMat.translate(1 - this.scaleX, 1 - this.scaleY);
// invert Y axis
this.transformMat.scale(1, -1);
}
WebGLRenderer.prototype.renderFrame = function(num){
if((this.renderedFrame == num && this.renderConfig.clearCanvas === true) || this.destroyed || num === -1){
return;
}
this.renderedFrame = num;
this.globalData.frameNum = num - this.animationItem._isFirstFrame;
this.globalData.frameId += 1;
this.globalData._mdf = !this.renderConfig.clearCanvas;
this.globalData.projectInterface.currentFrame = num;
// console.log('--------');
// console.log('NEW: ',num);
var i, len = this.layers.length;
if(!this.completeLayers){
this.checkLayers(num);
}
this.camera.prepareFrame(num);
for (i = 0; i < len; i++) {
if(this.completeLayers || this.elements[i]){
this.elements[i].prepareFrame(num - this.layers[i].st);
}
}
if(this.globalData._mdf) {
this.glContext.clearColor(0, 0, 0, 0);
this.glContext.clear(this.glContext.COLOR_BUFFER_BIT | this.glContext.DEPTH_BUFFER_BIT);
this.camera.renderFrame();
this.applyCameraTransformation();
// TODO: Look into rendering track mattes first
for (i = len - 1; i >= 0; i-=1) {
if(!this.elements[i].data.td) {
this.elements[i].renderFrame();
}
}
}
};