blob: 50ed9d912504280f7322c232f9b4e8fe98913a2e [file] [edit]
// Copyright 2018 The Immersive Web Community Group
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/*
Node for displaying 2D or stereo videos on a quad.
*/
import {Material} from '../core/material.js';
import {Primitive, PrimitiveAttribute} from '../core/primitive.js';
import {Node} from '../core/node.js';
import {VideoTexture} from '../core/texture.js';
const GL = WebGLRenderingContext; // For enums
class VideoMaterial extends Material {
constructor() {
super();
this.image = this.defineSampler('diffuse');
this.texCoordScaleOffset = this.defineUniform('texCoordScaleOffset',
[1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 0.0, 0.0], 4);
}
get materialName() {
return 'VIDEO_PLAYER';
}
get vertexSource() {
return `
uniform int EYE_INDEX;
uniform vec4 texCoordScaleOffset[2];
attribute vec3 POSITION;
attribute vec2 TEXCOORD_0;
varying vec2 vTexCoord;
vec4 vertex_main(mat4 proj, mat4 view, mat4 model) {
vec4 scaleOffset = texCoordScaleOffset[EYE_INDEX];
vTexCoord = (TEXCOORD_0 * scaleOffset.xy) + scaleOffset.zw;
vec4 out_vec = proj * view * model * vec4(POSITION, 1.0);
return out_vec;
}`;
}
get fragmentSource() {
return `
uniform sampler2D diffuse;
varying vec2 vTexCoord;
vec4 fragment_main() {
return texture2D(diffuse, vTexCoord);
}`;
}
}
export class VideoNode extends Node {
constructor(options) {
super();
this._video = options.video;
this._displayMode = options.displayMode || 'mono';
this._video_texture = new VideoTexture(this._video);
}
get aspectRatio() {
let width = this._video.videoWidth;
let height = this._video.videoHeight;
switch (this._displayMode) {
case 'stereoTopBottom': height *= 0.5; break;
case 'stereoLeftRight': width *= 0.5; break;
}
if (!height || !width) {
return 1;
}
return width / height;
}
onRendererChanged(renderer) {
let vertices = [
-1.0, 1.0, 0.0, 0.0, 0.0,
1.0, 1.0, 0.0, 1.0, 0.0,
1.0, -1.0, 0.0, 1.0, 1.0,
-1.0, -1.0, 0.0, 0.0, 1.0,
];
let indices = [
0, 2, 1,
0, 3, 2,
];
let vertexBuffer = renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(vertices));
let indexBuffer = renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices));
let attribs = [
new PrimitiveAttribute('POSITION', vertexBuffer, 3, GL.FLOAT, 20, 0),
new PrimitiveAttribute('TEXCOORD_0', vertexBuffer, 2, GL.FLOAT, 20, 12),
];
let primitive = new Primitive(attribs, indices.length);
primitive.setIndexBuffer(indexBuffer);
primitive.setBounds([-1.0, -1.0, 0.0], [1.0, 1.0, 0.015]);
let material = new VideoMaterial();
material.image.texture = this._video_texture;
switch (this._displayMode) {
case 'mono':
material.texCoordScaleOffset.value = [1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 0.0, 0.0];
break;
case 'stereoTopBottom':
material.texCoordScaleOffset.value = [1.0, 0.5, 0.0, 0.0,
1.0, 0.5, 0.0, 0.5];
break;
case 'stereoLeftRight':
material.texCoordScaleOffset.value = [0.5, 1.0, 0.0, 0.0,
0.5, 1.0, 0.5, 0.0];
break;
}
let renderPrimitive = renderer.createRenderPrimitive(primitive, material);
this.addRenderPrimitive(renderPrimitive);
}
}