324 lines
10 KiB
JavaScript
324 lines
10 KiB
JavaScript
"use strict"
|
|
|
|
var gl;
|
|
var program;
|
|
|
|
var initialClickPositionX = 0;
|
|
var initialClickPositionY = 0;
|
|
var isMouseDown = false;
|
|
var clickedGridBlockX = 0;
|
|
var clickedGridBlockY = 0;
|
|
|
|
var fieldElements;
|
|
|
|
var dispositionInformation = new Int32Array(3);
|
|
|
|
const blockSize = 64;
|
|
|
|
function main(evt){
|
|
window.removeEventListener(evt.type, setupWebGL, false);
|
|
setupControls();
|
|
setupWebGL();
|
|
}
|
|
|
|
function setupWebGL () {
|
|
if (!(gl = getRenderingContext()))
|
|
return;
|
|
|
|
|
|
// setup GLSL program
|
|
|
|
var source = document.querySelector("#vertex-shader").innerHTML;
|
|
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
gl.shaderSource(vertexShader,source);
|
|
gl.compileShader(vertexShader);
|
|
source = document.querySelector("#fragment-shader").innerHTML;
|
|
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
gl.shaderSource(fragmentShader,source);
|
|
gl.compileShader(fragmentShader);
|
|
|
|
program = gl.createProgram();
|
|
gl.attachShader(program, vertexShader);
|
|
gl.attachShader(program, fragmentShader);
|
|
gl.linkProgram(program);
|
|
gl.detachShader(program, vertexShader);
|
|
gl.detachShader(program, fragmentShader);
|
|
gl.deleteShader(vertexShader);
|
|
gl.deleteShader(fragmentShader);
|
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
var linkErrLog = gl.getProgramInfoLog(program);
|
|
cleanup();
|
|
console.log("Shader program did not link successfully. "
|
|
+ "Error log: " + linkErrLog);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//const vertexIdLoc = gl.getAttribLocation(program, 'vertexId');
|
|
const resolutionLoc = gl.getUniformLocation(program, 'resolution');
|
|
const fieldLayoutLoc = gl.getUniformLocation(program, 'fieldLayout');
|
|
const dispositionInformationLoc = gl.getUniformLocation(program, 'dispositionInformation');
|
|
|
|
// Make a buffer with just a count in it.
|
|
|
|
const numVerts = 4;
|
|
//const vertexIds = new Float32Array(numVerts);
|
|
//vertexIds.forEach((v, i) => {
|
|
// vertexIds[i] = i;
|
|
//});
|
|
|
|
fieldElements = new Float32Array(16);
|
|
fieldElements.forEach((v, i) => {
|
|
fieldElements[i] = i;
|
|
});
|
|
|
|
Shuffle(fieldElements);
|
|
|
|
|
|
dispositionInformation[0] = 1;
|
|
dispositionInformation[1] = 0;
|
|
dispositionInformation[2] = 0;
|
|
|
|
//const idBuffer = gl.createBuffer();
|
|
//gl.bindBuffer(gl.ARRAY_BUFFER, idBuffer);
|
|
//gl.bufferData(gl.ARRAY_BUFFER, vertexIds, gl.STATIC_DRAW);
|
|
|
|
// draw
|
|
function render(timeStamp) {
|
|
var canvas = document.getElementById("canvas");
|
|
canvas.width = canvas.clientWidth;
|
|
canvas.height = canvas.clientHeight;
|
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
|
|
gl.useProgram(program);
|
|
|
|
//{
|
|
// // Turn on the attribute
|
|
// gl.enableVertexAttribArray(vertexIdLoc);
|
|
//
|
|
// // Bind the id buffer.
|
|
// gl.bindBuffer(gl.ARRAY_BUFFER, idBuffer);
|
|
//
|
|
// // Tell the attribute how to get data out of idBuffer (ARRAY_BUFFER)
|
|
// const size = 1; // 1 components per iteration
|
|
// const type = gl.FLOAT; // the data is 32bit floats
|
|
// const normalize = false; // don't normalize the data
|
|
// const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
|
|
// const offset = 0; // start at the beginning of the buffer
|
|
// gl.vertexAttribPointer(vertexIdLoc, size, type, normalize, stride, offset);
|
|
//}
|
|
|
|
// tell the shader the resolution
|
|
gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
|
|
|
|
gl.uniformMatrix4fv(fieldLayoutLoc, false, fieldElements);
|
|
|
|
gl.uniform3iv(dispositionInformationLoc, dispositionInformation);
|
|
|
|
gl.drawArrays(gl.TRIANGLE_FAN, 0, numVerts);
|
|
requestAnimationFrame(render);
|
|
}
|
|
|
|
requestAnimationFrame(render);
|
|
return;
|
|
|
|
|
|
// gl.disable(gl.BLEND);
|
|
// gl.disable(gl.CULL_FACE);
|
|
// gl.disable(gl.DEPTH_TEST);
|
|
// gl.disable(gl.DITHER);
|
|
// gl.disable(gl.POLYGON_OFFSET_FILL);
|
|
// gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE);
|
|
// gl.disable(gl.SAMPLE_COVERAGE);
|
|
// gl.disable(gl.SCISSOR_TEST);
|
|
// gl.disable(gl.STENCIL_TEST);
|
|
|
|
cleanup();
|
|
}
|
|
|
|
var buffer;
|
|
function initializeAttributes() {
|
|
// gl.enableVertexAttribArray(0);
|
|
// buffer = gl.createBuffer();
|
|
// gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
// gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0);
|
|
}
|
|
|
|
function Shuffle(array2D) {
|
|
for (var i = 0; i < array2D.length; i++) {
|
|
var randomIdx1 = Math.floor(Math.random() * (i + 1));
|
|
var temp = array2D[i];
|
|
array2D[i] = array2D[randomIdx1];
|
|
array2D[randomIdx1] = temp;
|
|
}
|
|
return array2D
|
|
}
|
|
|
|
function iMod(x, N){
|
|
return (x % N + N) %N;
|
|
}
|
|
|
|
function setupControls(){
|
|
function onMouseMove(e) {
|
|
if(window.TouchEvent && e instanceof TouchEvent){
|
|
e = e.touches[0];
|
|
}
|
|
if(!isMouseDown) return;
|
|
|
|
const rect = canvas.getBoundingClientRect();
|
|
|
|
var mouseX = e.clientX - rect.left;
|
|
var mouseY = e.clientY - rect.top;
|
|
|
|
if(Math.abs(mouseX - initialClickPositionX) > Math.abs(mouseY - initialClickPositionY)){
|
|
dispositionInformation[0] = 1;
|
|
dispositionInformation[1] = clickedGridBlockY;
|
|
dispositionInformation[2] = mouseX - initialClickPositionX;
|
|
}else{
|
|
dispositionInformation[0] = 0;
|
|
dispositionInformation[1] = clickedGridBlockX;
|
|
dispositionInformation[2] = mouseY - initialClickPositionY;
|
|
}
|
|
|
|
|
|
|
|
// initialClickPositionX = mouseX;
|
|
// initialClickPositionY = mouseY;
|
|
}
|
|
|
|
function onMouseDown(e) {
|
|
if(window.TouchEvent && e instanceof TouchEvent){
|
|
e = e.touches[0];
|
|
}
|
|
|
|
const rect = canvas.getBoundingClientRect();
|
|
|
|
initialClickPositionX = e.clientX - rect.left;
|
|
initialClickPositionY = e.clientY - rect.top;
|
|
|
|
|
|
var xFragCoord = Math.trunc(initialClickPositionX - Math.trunc(rect.width / 2.0));
|
|
var yFragCoord = Math.trunc(initialClickPositionY - Math.trunc(rect.height / 2.0));
|
|
|
|
var xGridIndex = Math.trunc(xFragCoord / 64);
|
|
xGridIndex = (xFragCoord) < 0 ? xGridIndex - 1 : xGridIndex;
|
|
var yGridIndex = Math.trunc(yFragCoord / 64);
|
|
yGridIndex = (yFragCoord) < 0 ? yGridIndex - 1 : yGridIndex;
|
|
|
|
clickedGridBlockX = iMod(xGridIndex, 4);
|
|
clickedGridBlockY = iMod(yGridIndex, 4);
|
|
|
|
|
|
isMouseDown = true;
|
|
}
|
|
function onMouseUp(e) {
|
|
if(window.TouchEvent && e instanceof TouchEvent){
|
|
e = e.touches[0];
|
|
}
|
|
|
|
function vecRot(arr, rotateAmount, length){
|
|
// Storing rotated version of array
|
|
var temp = new Int32Array(length);
|
|
|
|
// Keeping track of the current index
|
|
// of temp[]
|
|
var k = 0;
|
|
|
|
// Storing the n - d elements of
|
|
// array arr[] to the front of temp[]
|
|
for (var i = rotateAmount; i < length; i++) {
|
|
temp[k] = arr[i];
|
|
k++;
|
|
}
|
|
|
|
// Storing the first d elements of array arr[]
|
|
// into temp
|
|
for (var i = 0; i < rotateAmount; i++) {
|
|
temp[k] = arr[i];
|
|
k++;
|
|
}
|
|
|
|
// Copying the elements of temp[] in arr[]
|
|
// to get the final rotated array
|
|
for (var i = 0; i < length; i++) {
|
|
arr[i] = temp[i];
|
|
}
|
|
}
|
|
function matRot(matrix, columnOrRow, rowIndex, rotateAmount){
|
|
// Storing rotated version of array
|
|
var temp = new Int32Array(4);
|
|
|
|
if(columnOrRow != 0){
|
|
for(var i = 0; i < 4; i++){
|
|
temp[i] = matrix[rowIndex * 4 + i];
|
|
}
|
|
|
|
vecRot(temp, rotateAmount, 4);
|
|
|
|
for(var i = 0; i < 4; i++){
|
|
matrix[rowIndex * 4 + i] = temp[i];
|
|
}
|
|
}else{
|
|
for(var i = 0; i < 4; i++){
|
|
temp[i] = matrix[i * 4 + rowIndex];
|
|
}
|
|
|
|
vecRot(temp, rotateAmount, 4);
|
|
|
|
for(var i = 0; i < 4; i++){
|
|
matrix[i * 4 + rowIndex] = temp[i];
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
isMouseDown = false;
|
|
|
|
var rotateAmount = Math.round(-dispositionInformation[2] / 64);
|
|
rotateAmount = iMod(rotateAmount, 4);
|
|
|
|
matRot(fieldElements, dispositionInformation[0], dispositionInformation[1], rotateAmount);
|
|
|
|
dispositionInformation[0] = 0;
|
|
dispositionInformation[1] = 0;
|
|
dispositionInformation[2] = 0;
|
|
|
|
}
|
|
|
|
canvas.addEventListener('mousemove', onMouseMove);
|
|
canvas.addEventListener('mousedown', onMouseDown);
|
|
canvas.addEventListener('mouseup', onMouseUp);
|
|
|
|
canvas.addEventListener('touchmove', onMouseMove);
|
|
canvas.addEventListener('touchstart', onMouseDown);
|
|
canvas.addEventListener('touchend', onMouseUp);
|
|
}
|
|
|
|
function cleanup() {
|
|
gl.useProgram(null);
|
|
if (buffer)
|
|
gl.deleteBuffer(buffer);
|
|
if (program)
|
|
gl.deleteProgram(program);
|
|
}
|
|
|
|
function getRenderingContext() {
|
|
var canvas = document.getElementById("canvas");
|
|
canvas.width = canvas.clientWidth;
|
|
canvas.height = canvas.clientHeight;
|
|
var gl = canvas.getContext("webgl2")
|
|
if(gl == null){
|
|
gl = canvas.getContext("experimental-webgl");
|
|
}
|
|
if (gl == null) {
|
|
return null;
|
|
}
|
|
//gl.viewport(0, 0);
|
|
//gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
//gl.clipControl(gl.UPPER_LEFT, gl.ZERO_TO_ONE)
|
|
return gl;
|
|
} |