<!DOCTYPE html>
<!--
/*
* Copyright (c) 2012 Frederick Ackers. All rights reserved.
* Based on code from Apple example code
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-->
<html>
<head>
<title>Molecular 3D Viewer</title>
<script type="text/javascript" src="webgl-utils.js"></script>
<script type="text/javascript" src="webgl-debug.js"></script>
<script src="J3DI.js"> </script>
<script src="J3DIMath.js" type="text/javascript"> </script>
<script type="text/javascript" src="cameracontroller.js"></script>
<script id="vshader" type="x-shader/x-vertex">
uniform mat4 u_modelViewProjMatrix;
uniform mat4 u_normalMatrix;
uniform vec3 lightDir;
attribute vec3 vNormal;
attribute vec4 vTexCoord;
attribute vec4 vPosition;
varying float v_Dot;
varying vec2 v_texCoord;
void main()
{
gl_Position = u_modelViewProjMatrix * vPosition;
v_texCoord = vTexCoord.st;
vec4 transNormal = u_normalMatrix * vec4(vNormal,1);
v_Dot = max(dot(transNormal.xyz, lightDir), 0.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D sampler2d;
varying float v_Dot;
varying vec2 v_texCoord;
void main()
{
vec4 color = texture2D(sampler2d,v_texCoord);
color += vec4(0.1,0.1,0.1,1);
gl_FragColor = vec4(color.xyz * v_Dot, color.a);
}
</script>
<script>
const minIncAngle = 0.2;
const maxIncAngle = 2;
var g = {}; // globals
var controller = null;
var g_ctx = null;
var objects =new Array();
var object_count = 0;
var setcamera = false;
function init()
{
var gl = initWebGL("molview");
if (!gl) {
return;
}
var c = document.getElementById("molview");
//c = WebGLDebugUtils.makeLostContextSimulatingCanvas(c);
// tell the simulator when to lose context.
//c.loseContextInNCalls(15);
c.addEventListener('webglcontextlost', handleContextLost, false);
c.addEventListener('webglcontextrestored', handleContextRestored, false);
g.program = simpleSetup(gl, "vshader", "fshader",
[ "vNormal", "vTexCoord", "vPosition"],
[ 0, 0, 0, 1 ], 10000);
gl.uniform3f(gl.getUniformLocation(g.program, "lightDir"), 0, 0, 1);
gl.uniform1i(gl.getUniformLocation(g.program, "sampler2d"), 0);
if (g.program) {
g.u_normalMatrixLoc = gl.getUniformLocation(g.program, "u_normalMatrix");
g.u_modelViewProjMatrixLoc = gl.getUniformLocation(g.program, "u_modelViewProjMatrix");
}
g.sphere = makeSphere(gl, 1, 30, 30);
// get the images
earthTexture = loadImageTexture(gl, "./c1.jpg");
molTexture = loadImageTexture(gl, "./h1.jpg");
controller = new CameraController(c);
// Try the following (and uncomment the "pointer-events: none;" in
// the index.html) to try the more precise hit detection
// controller = new CameraController(document.getElementById("body"), c, gl);
controller.onchange = function(xRot, yRot) {
drawPicture(g_ctx);
};
controller.onnewposition = function(xPos, yPos, zPos) {
drawPicture(g_ctx);
};
return gl;
}
width = -1;
height = -1;
var requestId;
function reshape(ctx)
{
var canvas = document.getElementById('molview');
if (canvas.width == width && canvas.height == height)
return;
width = canvas.width;
height = canvas.height;
ctx.viewport(0, 0, width, height);
g.perspectiveMatrix = new J3DIMatrix4();
g.perspectiveMatrix.perspective(150, 1, 1, 10000);
g.perspectiveMatrix.lookat(0,0,20, 0, 0, 0, 0, 1, 0);
}
function drawOne(ctx, angle, x, y, z, scale, texture)
{
// setup VBOs
ctx.enableVertexAttribArray(0);
ctx.enableVertexAttribArray(1);
ctx.enableVertexAttribArray(2);
ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.vertexObject);
ctx.vertexAttribPointer(2, 3, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.normalObject);
ctx.vertexAttribPointer(0, 3, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.texCoordObject);
ctx.vertexAttribPointer(1, 2, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, g.sphere.indexObject);
// generate the model-view matrix
var mvMatrix = new J3DIMatrix4();
// Add in camera controller's rotation
var pos = controller.getPosition();
mvMatrix.translate(pos[0],pos[1],pos[2]);
mvMatrix.rotate(controller.getRoll(), 1, 0, 0);
mvMatrix.rotate(controller.getYaw(), 0, 1, 0);
mvMatrix.rotate(controller.getPitch(), 0, 0, 1);
//mvMatrix.rotate(controller.zRot, 0, 0, 1);
mvMatrix.translate(-x,-y,-z);
//mvMatrix.translate(x,y,z);
mvMatrix.rotate(30, 1,0,0);
mvMatrix.rotate(angle, 0,1,0);
mvMatrix.scale(scale, scale, scale);
// construct the normal matrix from the model-view matrix
var normalMatrix = new J3DIMatrix4(mvMatrix);
normalMatrix.invert();
normalMatrix.transpose();
normalMatrix.setUniform(ctx, g.u_normalMatrixLoc, false);
// construct the model-view * projection matrix
var mvpMatrix = new J3DIMatrix4(g.perspectiveMatrix);
mvpMatrix.multiply(mvMatrix);
mvpMatrix.setUniform(ctx, g.u_modelViewProjMatrixLoc, false);
ctx.bindTexture(ctx.TEXTURE_2D, texture);
ctx.drawElements(ctx.TRIANGLES, g.sphere.numIndices, ctx.UNSIGNED_SHORT, 0);
}
function drawPicture(ctx)
{
reshape(ctx);
ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT);
for (i = 0; i < object_count; ++i) {
if (objects[i][0] == "ATOM")
{
if (setcamera != true)
{
g.perspectiveMatrix.lookat(0, 0, objects[i][7], 0, 0, 0, 0, 1, 0);
setcamera = true;
}
drawOne(ctx, 30,
objects[i][5],
objects[i][6],
objects[i][7],
0.75,
molTexture);
}
}
ctx.bindTexture(ctx.TEXTURE_2D, null);
framerate.snapshot();
}
function readSingleFile(evt) {
//Retrieve the first (and only!) File from the FileList object
var f = evt[0];
if (f)
{
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
alert( "Got the file.\n"
+"name: " + f.name + "\n"
+"type: " + f.type + "\n"
+"size: " + f.size + " bytes\n"
+ "starts with: " + contents);
var lines = contents.split("\n");
object_count = 0;
objects = [];
for (i=0; i < lines.length; i++)
{
//alert(lines[i]);
var singleLine = lines[i].split(" ");
for (x = 0; x < singleLine.length; x++)
{
objects[object_count] = new Array();
var counter = 0;
for (y = 0; y < singleLine.length; y++)
{
if (singleLine[y]!="" && singleLine[y]!=",")
objects[object_count][counter++] = singleLine[y];
}
x = singleLine.length;
object_count++;
setcamera = false;
//controller.setZoomFactor(0.35);
//alert("Array reads: "+objects[object_count-1]);
}
}
controller.reset();
}
r.readAsText(f);
drawPicture(g_ctx);
}
else
{
alert("Failed to load file");
}
}
function start()
{
var c = document.getElementById("molview");
var w = Math.floor(window.innerWidth * 0.7);
var h = Math.floor(window.innerHeight * 0.9);
//c = WebGLDebugUtils.makeLostContextSimulatingCanvas(c);
// tell the simulator when to lose context.
//c.loseContextInNCalls(1500);
c.addEventListener('webglcontextlost', handleContextLost, false);
c.addEventListener('webglcontextrestored', handleContextRestored, false);
c.width = w;
c.height = h;
g_ctx = init();
if (!g_ctx) {
return;
}
framerate = new Framerate("framerate");
var f = function() {
drawPicture(g_ctx)
requestId = window.requestAnimFrame(f, c);
};
f();
function handleContextLost(e) {
e.preventDefault();
clearLoadingImages();
if (requestId !== undefined) {
window.cancelRequestAnimFrame(requestId);
requestId = undefined;
}
}
function handleContextRestored() {
init();
f();
}
}
function handleContextLost(e) {
log("handle context lost");
e.preventDefault();
clearLoadingImages();
}
function handleContextRestored() {
log("handle context restored");
init();
}
function keyCamera(event){//a key is released
var cam = controller;
if(event.shiftKey) {
switch(event.keyCode) {//determine the key pressed
case 65://a key
cam.roll(-Math.PI * 0.25);//tilt to the left
break;
case 37://left arrow
cam.yaw(Math.PI * 0.25);//rotate to the left
break;
case 68://d key
cam.roll(Math.PI * 0.25);//tilt to the right
break;
case 39://right arrow
cam.yaw(-Math.PI * 0.25);//rotate to the right
break;
case 83://s key
case 40://down arrow
cam.pitch(Math.PI * 0.25);//look down
break;
case 87://w key
case 38://up arrow
cam.pitch(-Math.PI * 0.25);//look up
break;
}
}
else {
var pos = cam.getPosition();
//alert(pos);
switch(event.keyCode) {//deterime the key pressed
case 65://a key
case 37://left arrow
cam.setPosition(pos[0]-0.5,pos[1],pos[2]);//move - along the X axis
break;
case 68://d key
case 39://right arrow
cam.setPosition(pos[0]+0.5,pos[1],pos[2]);//more + along the X axis
break;
case 83://s key
cam.setPosition(pos[0],pos[1]-0.5,pos[2]);//move - along the Y axis (down)
break;
case 40://down arrow
cam.setPosition(pos[0],pos[1],pos[2]+0.5);//move + on the Z axis
break;
case 87://w key
cam.setPosition(pos[0],pos[1]+0.50,pos[2]);//move + on the Y axis (up)
break;
case 38://up arrow
cam.setPosition(pos[0],pos[1],pos[2]-0.5);//move - on the Z axis
break;
}
}
}
function reset(){
controller.reset();
}
//document.getElementById('fileinput').addEventListener('change', readSingleFile, false);
</script>
<style type="text/css">
canvas {
border: 2px solid black;
}
</style>
</head>
<body onload="start()" onkeydown="keyCamera(event)">
<table><tr><td width="70%">
<canvas id="molview">
There is supposed to be a Molecular 3D Viewer drawing here.
</canvas>
<div id="framerate"></div>
</td>
<td width="30%">
<p>The viewer takes a PDB file and parses it for the ATOM entries and displays them.<br />
Note: Large or complex molecules may be slow in viewer.
</p>
<input type="submit" value="Reset View" onclick="reset()">
<input type="file" id="fileinput" onchange="readSingleFile(this.files)">
<p>
Keys are: <br />
A: Move Along -X Axis<br />
W: Move Along +Y Axis<br />
S: Move Along -Y Axis<br />
D: Move Along +X Axis<br />
Left Arrow: Move Along -X Axis<br />
Right Arrow:Move Along +X Axis<br />
Down Arrow: Move Along +Z Axis<br />
Up Arrow: Move Along -Z Axis<br />
Shift+A: Tilt to the left <br />
Shift+W: Look Up<br />
Shift+S: Look Down<br />
Shift+D: Tile to the right<br />
Shift+Left Arrow: Rotate to the Left<br />
Shift+Right Arrow:Rotate to the right<br />
Shift+Down Arrow: Look Down<br />
Shift+Up Arrow: Look UP<br />
Mouse Drag Left: Rotate X<br />
Mouse Drag Right:Rotate X<br />
Mouse Drag Up: Rotate Y<br />
Mouse Drag Down: Rotate Y<br />
Mouse Wheel Forward: Zoom In<br />
Mouse Wheel Back: Zoom Out<br />
</p>
</td>
</tr>
</table>
</body>
</html>