mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-05 10:49:36 +02:00
285 lines
8.6 KiB
JavaScript
285 lines
8.6 KiB
JavaScript
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import * as Util from './util.js';
|
|
import WGLUPreserveGLState from 'gl-preserve-state';
|
|
|
|
var uiVS = [
|
|
'attribute vec2 position;',
|
|
|
|
'uniform mat4 projectionMat;',
|
|
|
|
'void main() {',
|
|
' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );',
|
|
'}',
|
|
].join('\n');
|
|
|
|
var uiFS = [
|
|
'precision mediump float;',
|
|
|
|
'uniform vec4 color;',
|
|
|
|
'void main() {',
|
|
' gl_FragColor = color;',
|
|
'}',
|
|
].join('\n');
|
|
|
|
var DEG2RAD = Math.PI/180.0;
|
|
|
|
// The gear has 6 identical sections, each spanning 60 degrees.
|
|
var kAnglePerGearSection = 60;
|
|
|
|
// Half-angle of the span of the outer rim.
|
|
var kOuterRimEndAngle = 12;
|
|
|
|
// Angle between the middle of the outer rim and the start of the inner rim.
|
|
var kInnerRimBeginAngle = 20;
|
|
|
|
// Distance from center to outer rim, normalized so that the entire model
|
|
// fits in a [-1, 1] x [-1, 1] square.
|
|
var kOuterRadius = 1;
|
|
|
|
// Distance from center to depressed rim, in model units.
|
|
var kMiddleRadius = 0.75;
|
|
|
|
// Radius of the inner hollow circle, in model units.
|
|
var kInnerRadius = 0.3125;
|
|
|
|
// Center line thickness in DP.
|
|
var kCenterLineThicknessDp = 4;
|
|
|
|
// Button width in DP.
|
|
var kButtonWidthDp = 28;
|
|
|
|
// Factor to scale the touch area that responds to the touch.
|
|
var kTouchSlopFactor = 1.5;
|
|
|
|
var Angles = [
|
|
0, kOuterRimEndAngle, kInnerRimBeginAngle,
|
|
kAnglePerGearSection - kInnerRimBeginAngle,
|
|
kAnglePerGearSection - kOuterRimEndAngle
|
|
];
|
|
|
|
/**
|
|
* Renders the alignment line and "options" gear. It is assumed that the canvas
|
|
* this is rendered into covers the entire screen (or close to it.)
|
|
*/
|
|
function CardboardUI(gl) {
|
|
this.gl = gl;
|
|
|
|
this.attribs = {
|
|
position: 0
|
|
};
|
|
this.program = Util.linkProgram(gl, uiVS, uiFS, this.attribs);
|
|
this.uniforms = Util.getProgramUniforms(gl, this.program);
|
|
|
|
this.vertexBuffer = gl.createBuffer();
|
|
this.gearOffset = 0;
|
|
this.gearVertexCount = 0;
|
|
this.arrowOffset = 0;
|
|
this.arrowVertexCount = 0;
|
|
|
|
this.projMat = new Float32Array(16);
|
|
|
|
this.listener = null;
|
|
|
|
this.onResize();
|
|
};
|
|
|
|
/**
|
|
* Tears down all the resources created by the UI renderer.
|
|
*/
|
|
CardboardUI.prototype.destroy = function() {
|
|
var gl = this.gl;
|
|
|
|
if (this.listener) {
|
|
gl.canvas.removeEventListener('click', this.listener, false);
|
|
}
|
|
|
|
gl.deleteProgram(this.program);
|
|
gl.deleteBuffer(this.vertexBuffer);
|
|
};
|
|
|
|
/**
|
|
* Adds a listener to clicks on the gear and back icons
|
|
*/
|
|
CardboardUI.prototype.listen = function(optionsCallback, backCallback) {
|
|
var canvas = this.gl.canvas;
|
|
this.listener = function(event) {
|
|
var midline = canvas.clientWidth / 2;
|
|
var buttonSize = kButtonWidthDp * kTouchSlopFactor;
|
|
// Check to see if the user clicked on (or around) the gear icon
|
|
if (event.clientX > midline - buttonSize &&
|
|
event.clientX < midline + buttonSize &&
|
|
event.clientY > canvas.clientHeight - buttonSize) {
|
|
optionsCallback(event);
|
|
}
|
|
// Check to see if the user clicked on (or around) the back icon
|
|
else if (event.clientX < buttonSize && event.clientY < buttonSize) {
|
|
backCallback(event);
|
|
}
|
|
};
|
|
canvas.addEventListener('click', this.listener, false);
|
|
};
|
|
|
|
/**
|
|
* Builds the UI mesh.
|
|
*/
|
|
CardboardUI.prototype.onResize = function() {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [
|
|
gl.ARRAY_BUFFER_BINDING
|
|
];
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
var vertices = [];
|
|
|
|
var midline = gl.drawingBufferWidth / 2;
|
|
|
|
// The gl buffer size will likely be smaller than the physical pixel count.
|
|
// So we need to scale the dps down based on the actual buffer size vs physical pixel count.
|
|
// This will properly size the ui elements no matter what the gl buffer resolution is
|
|
var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
|
|
var scalingRatio = gl.drawingBufferWidth / physicalPixels;
|
|
var dps = scalingRatio * window.devicePixelRatio;
|
|
|
|
var lineWidth = kCenterLineThicknessDp * dps / 2;
|
|
var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
|
|
var buttonScale = kButtonWidthDp * dps / 2;
|
|
var buttonBorder = ((kButtonWidthDp * kTouchSlopFactor) - kButtonWidthDp) * dps;
|
|
|
|
// Build centerline
|
|
vertices.push(midline - lineWidth, buttonSize);
|
|
vertices.push(midline - lineWidth, gl.drawingBufferHeight);
|
|
vertices.push(midline + lineWidth, buttonSize);
|
|
vertices.push(midline + lineWidth, gl.drawingBufferHeight);
|
|
|
|
// Build gear
|
|
self.gearOffset = (vertices.length / 2);
|
|
|
|
function addGearSegment(theta, r) {
|
|
var angle = (90 - theta) * DEG2RAD;
|
|
var x = Math.cos(angle);
|
|
var y = Math.sin(angle);
|
|
vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
|
|
vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
|
|
}
|
|
|
|
for (var i = 0; i <= 6; i++) {
|
|
var segmentTheta = i * kAnglePerGearSection;
|
|
|
|
addGearSegment(segmentTheta, kOuterRadius);
|
|
addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
|
|
addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
|
|
addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
|
|
addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
|
|
}
|
|
|
|
self.gearVertexCount = (vertices.length / 2) - self.gearOffset;
|
|
|
|
// Build back arrow
|
|
self.arrowOffset = (vertices.length / 2);
|
|
|
|
function addArrowVertex(x, y) {
|
|
vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
|
|
}
|
|
|
|
var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
|
|
|
|
addArrowVertex(0, buttonScale);
|
|
addArrowVertex(buttonScale, 0);
|
|
addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
|
|
addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
|
|
|
|
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
|
|
addArrowVertex(0, buttonScale);
|
|
addArrowVertex(buttonScale, buttonScale * 2);
|
|
addArrowVertex(buttonScale + angledLineWidth, (buttonScale * 2) - angledLineWidth);
|
|
|
|
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
|
|
addArrowVertex(0, buttonScale);
|
|
|
|
addArrowVertex(angledLineWidth, buttonScale - lineWidth);
|
|
addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
|
|
addArrowVertex(angledLineWidth, buttonScale + lineWidth);
|
|
addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
|
|
|
|
self.arrowVertexCount = (vertices.length / 2) - self.arrowOffset;
|
|
|
|
// Buffer data
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Performs distortion pass on the injected backbuffer, rendering it to the real
|
|
* backbuffer.
|
|
*/
|
|
CardboardUI.prototype.render = function() {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [
|
|
gl.CULL_FACE,
|
|
gl.DEPTH_TEST,
|
|
gl.BLEND,
|
|
gl.SCISSOR_TEST,
|
|
gl.STENCIL_TEST,
|
|
gl.COLOR_WRITEMASK,
|
|
gl.VIEWPORT,
|
|
|
|
gl.CURRENT_PROGRAM,
|
|
gl.ARRAY_BUFFER_BINDING
|
|
];
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
// Make sure the GL state is in a good place
|
|
gl.disable(gl.CULL_FACE);
|
|
gl.disable(gl.DEPTH_TEST);
|
|
gl.disable(gl.BLEND);
|
|
gl.disable(gl.SCISSOR_TEST);
|
|
gl.disable(gl.STENCIL_TEST);
|
|
gl.colorMask(true, true, true, true);
|
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
|
|
self.renderNoState();
|
|
});
|
|
};
|
|
|
|
CardboardUI.prototype.renderNoState = function() {
|
|
var gl = this.gl;
|
|
|
|
// Bind distortion program and mesh
|
|
gl.useProgram(this.program);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
gl.enableVertexAttribArray(this.attribs.position);
|
|
gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
|
|
|
|
gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
|
|
|
|
Util.orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
|
|
gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
|
|
|
|
// Draws UI element
|
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
|
|
gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
|
|
};
|
|
|
|
export default CardboardUI;
|