You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
11 KiB
360 lines
11 KiB
let ctrl = false, alt = false, shift = false, fpson = true, moving = false, over = false;
|
|
let lastClick = undefined;
|
|
let animating = true;
|
|
let flags = 0x0;
|
|
var startTime = Date.now();
|
|
let lastTime = Date.now();
|
|
var lastFrameTime = 0;
|
|
let oldDocument;
|
|
let fullscreen = false;
|
|
let oldparents = {};
|
|
var tr, div;
|
|
let canvas_originalsize;
|
|
let Sph = [];
|
|
let SphTr = [];
|
|
let SphDletaR = []
|
|
let selected = false, selection = -1, dragging = false;
|
|
for(let i = 0; i < ns; ++i)
|
|
{
|
|
SphTr[i]=matrix_identity();
|
|
SphDletaR[i] = 0;
|
|
}
|
|
function toggleFullscreen(element){
|
|
if(fullscreen)
|
|
{
|
|
if (document.exitFullscreen)
|
|
document.exitFullscreen();
|
|
else if (document.webkitExitFullscreen)
|
|
document.webkitExitFullscreen();
|
|
else if (document.mozCancelFullScreen)
|
|
document.mozCancelFullScreen();
|
|
else if (document.msExitFullscreen)
|
|
document.msExitFullscreen();
|
|
fullscreen = false;
|
|
bnfs.innerText = "Fullscreen";
|
|
}
|
|
else{
|
|
if(element.requestFullscreen)
|
|
element.requestFullscreen();
|
|
else if (element.webkitRequestFullscreen)
|
|
element.webkitRequestFullscreen();
|
|
else if(element.msRequestFullscreen)
|
|
element.msRequestFullscreen();
|
|
fullscreen = true;
|
|
bnfs.innerText = "Exit Fullscreen";
|
|
}
|
|
}
|
|
bnfs.onclick = function(_){
|
|
if(fullscreen){
|
|
oldparents[controls].appendChild(controls);
|
|
oldparents[canvas1].appendChild(canvas1);
|
|
canvas1.style.width = canvas_originalsize[0];
|
|
canvas1.style.height = canvas_originalsize[1];
|
|
howitworks.hidden = false;
|
|
}else{
|
|
div = document.createElement("div");
|
|
tr = document.createElement("table").insertRow();
|
|
tr.style.backgroundColor="white";
|
|
let size = Math.min(screen.availHeight, screen.availWidth);
|
|
canvas_originalsize = [canvas1.style.width, canvas1.style.height, canvas1.width, canvas1.height];
|
|
canvas1.style.height = canvas1.style.width = size;
|
|
howitworks.hidden=true;
|
|
oldparents[controls] = controls.parentNode;
|
|
oldparents[canvas1] = canvas1.parentNode;
|
|
|
|
let td1 = tr.insertCell();
|
|
td1.appendChild(canvas1);
|
|
let td2;
|
|
td2 = tr.insertCell();
|
|
td2.style.verticalAlign="top";
|
|
td2.appendChild(controls);
|
|
|
|
div.appendChild(tr);
|
|
document.body.appendChild(div);
|
|
}
|
|
toggleFullscreen(div);
|
|
}
|
|
clrsel.onclick=function(_){
|
|
setUniform("1i", "sel", -1);
|
|
selected = false;
|
|
selection = -1;
|
|
}
|
|
reset.onclick = function(_){
|
|
clrsel.onclick();
|
|
if(!animating)
|
|
pause_resume();
|
|
flags = 0;
|
|
moving = false;
|
|
mousedx = mousedy = mousedz = 0;
|
|
positionsupdated = true;
|
|
for(let i = 0; i < ns; ++i)
|
|
{
|
|
SphTr[i]=matrix_identity();
|
|
SphDletaR[i] = 0;
|
|
}
|
|
rtx.src='./RTXon.svg';
|
|
setUniform('1i', 'flags', flags);
|
|
}
|
|
bns.onclick=function(e){
|
|
if(ins.value>0 &&ins.value<=ns &&cns!=ins.value)
|
|
{
|
|
cns = ins.value;
|
|
fragmentShaderDefs = '\n const int cns = ' + cns + ';';
|
|
if(typeof canvas1.setShaders === "function")
|
|
canvas1.setShaders(vs, editor.getSession().getValue());
|
|
}
|
|
}
|
|
bnsamp.onclick=function(e){
|
|
let multiplier = insamp.value;
|
|
let w = parseInt(canvas1.style.width)*multiplier;
|
|
let h = parseInt(canvas1.style.height)*multiplier;
|
|
canvas1.height = h;
|
|
canvas1.width = w;
|
|
gl.viewport(0, 0, w, h);
|
|
//gl.clearRect(0, 0, w, h);
|
|
}
|
|
// SET UP THE EDITABLE TEXT AREA ON THE LEFT SIDE.
|
|
ace.require("ace/ext/language_tools");
|
|
var editor = ace.edit("ace", {
|
|
mode:"ace/mode/glsl",
|
|
theme:"ace/theme/crimson_editor"
|
|
});
|
|
editor.setOptions({
|
|
enableBasicAutocompletion: true,
|
|
enableSnippets: true,
|
|
enableLiveAutocompletion: true,
|
|
fontSize: 14,
|
|
fontFamily: "monaco, menlo, ubuntu mono, consolas, source-code-pro",
|
|
fixedWidthGutter: true,
|
|
showGutter: true,
|
|
showPrintMargin: false,
|
|
});
|
|
editor.setAutoScrollEditorIntoView(true);
|
|
if(fs != undefined)
|
|
editor.getSession().setValue(fs);
|
|
editor.session.on('change', function(delta) {
|
|
if(typeof canvas1.setShaders === "function")
|
|
{
|
|
canvas1.setShaders(vs, editor.getSession().getValue());
|
|
setUniform('1i', 'flags', flags);
|
|
}
|
|
});
|
|
// REPARSE THE SHADER PROGRAM AFTER EVERY KEYSTROKE.
|
|
delete editor.KeyBinding;
|
|
|
|
|
|
let pause_resume = function(){
|
|
if(animating)
|
|
lastTime = Date.now();
|
|
else
|
|
startTime += Date.now() - lastTime;
|
|
animating = !animating;
|
|
};
|
|
canvas1.addEventListener('click',function(ev){
|
|
if(!(shift && alt) && lastClick&& Date.now()-lastClick<400)
|
|
pause_resume();
|
|
lastClick = Date.now();
|
|
|
|
});
|
|
canvas1.addEventListener('mouseover', function(e){
|
|
over = true;
|
|
const mask = 0x8;
|
|
flags |= mask;
|
|
setUniform('1i', 'flags', flags);
|
|
});
|
|
canvas1.addEventListener('mousedown', function(e){
|
|
moving = true
|
|
mouselastX = mouselastY = undefined;
|
|
let i = hitTest([2*e.offsetX/ parseInt(canvas1.style.width)-1,
|
|
1-2*e.offsetY/ parseInt(canvas1.style.height), -1]);
|
|
if(i >= 0)
|
|
{
|
|
dragging = true;
|
|
selected = true;
|
|
setUniform("1i", "sel", i);
|
|
selection = i;
|
|
}
|
|
else if(selected = true){
|
|
dragging = false;
|
|
selected = false;
|
|
setUniform("1i", "sel", i);
|
|
selection = i;
|
|
}
|
|
});
|
|
canvas1.addEventListener('mousemove', function(e){
|
|
if(!(mouselastX==undefined || mouselastY == undefined)&&moving){
|
|
let dx = (mouselastX - e.offsetX),
|
|
dy = (mouselastY - e.offsetY);
|
|
if(!selected)
|
|
{
|
|
mousedx -= dx/60;
|
|
mousedy -= dy/60;
|
|
positionsupdated = true;
|
|
}else if(dragging){
|
|
let m = matrix_rotateY(-mousedx);
|
|
m = matrix_multiply(m, matrix_rotateX(-mousedy));
|
|
let dv = matrix_multiply(m, [2*-dx/ parseInt(canvas1.style.width),
|
|
2*dy/ parseInt(canvas1.style.height), 0, 1]).slice(0,3);
|
|
SphTr[selection] = matrix_multiply(SphTr[selection], matrix_translate(dv[0], dv[1], dv[2]));
|
|
}
|
|
}
|
|
mouselastX = e.offsetX;
|
|
mouselastY = e.offsetY;
|
|
});
|
|
canvas1.addEventListener('mouseup', function(e){
|
|
moving = false;
|
|
dragging = false;
|
|
});
|
|
canvas1.addEventListener('mouseout', function(e){
|
|
const mask = 0x8;
|
|
flags &= !mask;
|
|
setUniform('1i', 'flags', flags);
|
|
over = false;
|
|
moving = false;
|
|
});
|
|
canvas1.addEventListener('wheel', function(e){
|
|
if(!selected){
|
|
mousedz += e.wheelDelta/600;
|
|
positionsupdated = true;
|
|
}
|
|
else{
|
|
SphDletaR[selection] += e.wheelDelta / 800;
|
|
}
|
|
});
|
|
canvas1.scroll(function(e) {e.stopPropagation();});
|
|
rtx.style.cursor="pointer";
|
|
let rtswitch = function(){
|
|
alert('Ray Tracing is always on. See hw2 where rt can be toggled on/off.')
|
|
rtx.src='./RTXon.svg';
|
|
}
|
|
rtx.addEventListener('click', rtswitch);
|
|
var requestAnimationFrame = window.requestAnimationFrame ||
|
|
window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
|
|
let fpscounter = function(time){
|
|
if (start === undefined)
|
|
start = time;
|
|
else
|
|
fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
|
|
start = time;
|
|
if(fpson)
|
|
;//requestAnimationFrame(fpscounter);
|
|
else{
|
|
start = undefined;
|
|
fps.innerHTML = '';
|
|
}
|
|
};
|
|
document.addEventListener('keydown',(e)=>{
|
|
if(e.code.startsWith('Shift'))
|
|
shift = true;
|
|
if(e.code.startsWith('Control'))
|
|
ctrl = true;
|
|
if(e.code.startsWith('Alt'))
|
|
alt = true;
|
|
else if(ctrl && alt && e.code == 'KeyT'){
|
|
const mask = 0x1;
|
|
flags = flags&!mask | (!(flags&mask)?mask:0);
|
|
setUniform('1i', 'flags', flags);
|
|
}
|
|
else if (ctrl &&e.code == 'KeyS'){
|
|
let a = document.createElement('a');
|
|
a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
|
|
a.download = 'shader.frag';
|
|
a.click();
|
|
}
|
|
else if(ctrl && alt&&e.code == 'KeyR')
|
|
rtswitch();
|
|
else if(ctrl && alt&&e.code == 'KeyN')
|
|
{
|
|
reset.onclick();
|
|
}
|
|
else if(ctrl && alt&&e.code == 'KeyP')
|
|
pause_resume();
|
|
else if(ctrl && alt&&e.code == 'KeyF')
|
|
if(!fpson)
|
|
{
|
|
fpson = true;
|
|
requestAnimationFrame(fpscounter);
|
|
}
|
|
else
|
|
fpson = false;
|
|
|
|
if(fullscreen && selected ){
|
|
if(/*e.code == 'ArrowUp' || e.code == 'ArrowDown' || e.code =='ArrowLeft'
|
|
||e.code == 'ArrowRight' || e.code =='KeyW'||e.code =='KeyS'||*/e.code =='KeyF'||e.code =='KeyB'){
|
|
let m = matrix_rotateY(-mousedx);
|
|
m = matrix_multiply(m, matrix_rotateX(-mousedy));
|
|
m = const_multiply((fl + 1 + mousedz)/(fl+1), m);
|
|
|
|
switch(e.code){
|
|
// case 'ArrowUp':
|
|
// m = matrix_multiply(m, matrix_rotateX(0.1));
|
|
// break;
|
|
// case 'ArrowDown':
|
|
// m = matrix_multiply(m, matrix_rotateX(-0.1));
|
|
// break;
|
|
// case 'ArrowLeft':
|
|
// m = matrix_multiply(m, matrix_rotateY(-0.1));
|
|
// break;
|
|
// case 'ArrowRight':
|
|
// m = matrix_multiply(m, matrix_rotateY(0.1));
|
|
// break;
|
|
// case 'KeyW':
|
|
// m = matrix_multiply(m, matrix_rotateZ(0.1));
|
|
// break;
|
|
// case 'KeyS':
|
|
// m = matrix_multiply(m, matrix_rotateZ(-0.1));
|
|
// break;
|
|
case 'KeyB':
|
|
var dv = matrix_multiply(m, [0,0, -0.1, 1]).slice(0,3);
|
|
m = matrix_translate(dv[0], dv[1], dv[2]);
|
|
break;
|
|
case 'KeyF':
|
|
var dv = matrix_multiply(m, [0,0, 0.1, 1]).slice(0,3);
|
|
m = matrix_translate(dv[0], dv[1], dv[2]);
|
|
break;
|
|
}
|
|
SphTr[selection] = matrix_multiply(SphTr[selection], m);
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('keyup',(e)=>{
|
|
if(e.code.startsWith('Control'))
|
|
ctrl = false;
|
|
if(e.code.startsWith('Alt'))
|
|
alt = false;
|
|
if(e.code.startsWith('Shift'))
|
|
shift = false;
|
|
});
|
|
|
|
function animate(gl) {
|
|
let uTime;
|
|
if(animating)
|
|
{
|
|
uTime = (Date.now() - startTime) / 1000;
|
|
setUniform('1f', 'uTime', uTime);
|
|
}
|
|
else
|
|
{
|
|
uTime = (lastTime - startTime) / 1000;
|
|
setUniform('1f', 'uTime', uTime);
|
|
}
|
|
Sph[0] = [0,0.05*Math.cos(uTime + 1.),.045*Math.cos(uTime), 1,.15];
|
|
Sph[1] = [0,0,0,1,.25];
|
|
Sph[2] = [.22*Math.sin(uTime*1.2),0.05,.22*Math.cos(uTime*1.2),1,.05];
|
|
Sph[3] = [.9*Math.sin(uTime*.4),0.,.9*Math.cos(uTime*.4),1,.25];
|
|
Sph[4] = [0.5*Math.sin(uTime*1.),0.08*Math.sin(uTime *0.9),.5*Math.cos(uTime*1.),1,.12];
|
|
|
|
for(let i = 0; i < ns; ++ i)
|
|
{
|
|
let trsph = matrix_multiply(SphTr[i], Sph[i]);
|
|
trsph[3] = Sph[i][4];
|
|
setUniform('4fv', 'Sph['+ i + ']', trsph);
|
|
}
|
|
|
|
if(positionsupdated)
|
|
updatePositions();
|
|
}
|
|
|
|
requestAnimationFrame(fpscounter);
|