diff --git a/src/js/GLmol.js b/src/js/GLmol.js index cfe3914..88fc97c 100644 --- a/src/js/GLmol.js +++ b/src/js/GLmol.js @@ -1,5 +1,5 @@ /* - GLmol - Molecular Viewer on WebGL/Javascript (0.40) + GLmol - Molecular Viewer on WebGL/Javascript (0.40 + VTF) (C) Copyright 2011-2012, biochem_fan License: dual license of MIT or LGPL3 @@ -31,6 +31,38 @@ THREE.Matrix4.prototype.isIdentity = function() { return true; }; +function hookShader() { // Lambert Shader and Line Shader ONLY +// For texture-coordinates, see +// http://stackoverflow.com/questions/5879403/opengl-texture-coordinates-in-pixel-space/5879551#5879551 +// This is the heart of this trick. +// FaceColors, VertexColors: USE_COLOR is defined, color is passed as "color" attribute +// Other cases: color is passed as "diffuse" uniform + +// USE_MAP has to be disabled; otherwise, mesh without uv will not be displayed. +// Inject Color picker into vertex shader + THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace("void main", "#undef USE_MAP\n uniform sampler2D map; \n \n\nvec3 pickColor(vec3 color){\n int serial = int(color.b * 255.0 + color.g * 65280.0 + color.r * 16711680.0 + 0.01); float x = ((mod(float(serial), 512.0))* 2.0 + 1.0) / 1024.0, y = (float(serial / 512) * 2.0 + 1.0) / 1024.0;\n \n return texture2D(map, vec2(x, y)).rgb;\n} \n\n\nvoid main"); +// Hook Material color ("diffuse" uniform) + THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace(/\* diffuse/g, "* diffuse2"); + THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace("vLightFront = vLightFront *", "///////////////////////////////////////\n\n#ifndef USE_COLOR\nvec3 diffuse2 = pickColor(diffuse).rgb;\n#else\nvec3 diffuse2 = diffuse;\n#endif\nvLightFront = vLightFront *"); +// Hook vertex color & face color ("color" attribute) + THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace("vColor = color;", "vColor = pickColor(color);"); + THREE.ShaderLib.lambert.vertexShader = THREE.ShaderLib.lambert.vertexShader.replace("vColor = color * color;", "vColor = pickColor(color) * pickColor(color);"); +// Disable normal texture mapping + THREE.ShaderLib.lambert.fragmentShader = THREE.ShaderLib.lambert.fragmentShader.replace("void main", "#undef USE_MAP\n void main"); + THREE.ShaderLib.lambert.fragmentShader = THREE.ShaderLib.lambert.fragmentShader.replace("gl_FragColor = gl_FragColor * texture2D( map, vUv );", ""); + THREE.ShaderLib.lambert.fragmentShader = THREE.ShaderLib.lambert.fragmentShader.replace("gl_FragColor = gl_FragColor * texelColor;", "a1"); + +// Same for 'basic' shader +// For this to work, WebGLRenderer.js has to be patched beforehand. + THREE.ShaderLib.basic.vertexShader = THREE.ShaderLib.basic.vertexShader.replace("void main", "uniform sampler2D map; \n \n\nvec3 pickColor(vec3 color){\n int serial = int(color.b * 255.0 + color.g * 65280.0 + color.r * 16711680.0 + 0.01); float x = ((mod(float(serial), 512.0))* 2.0 + 1.0) / 1024.0, y = (float(serial / 512) * 2.0 + 1.0) / 1024.0;\n \n return texture2D(map, vec2(x, y)).rgb;\n} \n\n\nvoid main"); + THREE.ShaderLib.basic.vertexShader = THREE.ShaderLib.basic.vertexShader.replace(/\* diffuse/g, "* diffuse2"); + THREE.ShaderLib.basic.vertexShader = THREE.ShaderLib.basic.vertexShader.replace("vLightFront = vLightFront *", "///////////////////////////////////////\n\n#ifndef USE_COLOR\nvec3 diffuse2 = pickColor(diffuse).rgb;\n#else\nvec3 diffuse2 = diffuse;\n#endif\nvLightFront = vLightFront *"); + THREE.ShaderLib.basic.vertexShader = THREE.ShaderLib.basic.vertexShader.replace("vColor = color;", "vColor = pickColor(color);"); + THREE.ShaderLib.basic.fragmentShader = THREE.ShaderLib.basic.fragmentShader.replace("gl_FragColor = gl_FragColor * texture2D( map, vUv );", ""); +} + +hookShader(); + var GLmol = (function() { function GLmol(id, suppressAutoload) { this.Nucleotides = [' G', ' A', ' T', ' C', ' U', ' DG', ' DA', ' DT', ' DC', ' DU']; @@ -113,11 +145,31 @@ function GLmol(id, suppressAutoload) { this.currentModelPos = 0; this.cz = 0; this.enableMouse(); + this.colortable = new Uint8Array(512 * 512 * 3); + this.colormap = new THREE.DataTexture(this.colortable, 512, 512, THREE.RGBFormat); +// this.colormap.generateMipmaps = false; + this.colormap.onUpdate = function() {console.log('texture updated');}; + this.colormap.magFilter = this.colormap.minFilter = THREE.NearestFilter; + this.colormap.generateMipmaps = false; + for (var i = 0; i < 512 * 512; i++) { + this.setColor(i, 0x0000ff); + } if (suppressAutoload) return; this.loadMolecule(); } +GLmol.prototype.setColor = function(serial, color) { + var b = color % 256; + var g = Math.floor((color % 65536) / 256); + var r = Math.floor(color / 65536); + this.colortable[serial * 3] = r; + this.colortable[serial * 3 + 1] = g; + this.colortable[serial * 3 + 2] = b; + this.colormap.needsUpdate = true; +} + + GLmol.prototype.setupLights = function(scene) { var directionalLight = new THREE.DirectionalLight(0xFFFFFF); directionalLight.position = new TV3(0.2, 0.2, -1).normalize(); @@ -198,7 +250,7 @@ GLmol.prototype.parsePDB2 = function(str) { else hetflag = false; atoms[serial] = {'resn': resn, 'x': x, 'y': y, 'z': z, 'elem': elem, 'hetflag': hetflag, 'chain': chain, 'resi': resi, 'serial': serial, 'atom': atom, - 'bonds': [], 'ss': 'c', 'color': 0xFFFFFF, 'bonds': [], 'bondOrder': [], 'b': b /*', altLoc': altLoc*/}; + 'bonds': [], 'ss': 'c', 'color': serial, 'bonds': [], 'bondOrder': [], 'b': b /*', altLoc': altLoc*/}; } else if (recordName == 'SHEET ') { var startChain = line.substr(21, 1); var startResi = parseInt(line.substr(22, 4)); @@ -325,11 +377,12 @@ GLmol.prototype.subdivide = function(_points, DIV) { // points as Vector3 GLmol.prototype.drawAtomsAsSphere = function(group, atomlist, defaultRadius, forceDefault) { var sphereGeometry = new THREE.SphereGeometry(1, this.sphereQuality, this.sphereQuality); // r, seg, ring + sphereGeometry.faceVertexUvs = []; for (var i = 0; i < atomlist.length; i++) { var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - var sphereMaterial = new THREE.MeshLambertMaterial({color: atom.color}); + var sphereMaterial = new THREE.MeshLambertMaterial({color: atom.color, map:this.colormap}); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); group.add(sphere); var r = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius @@ -347,7 +400,7 @@ GLmol.prototype.drawAtomsAsIcosahedron = function(group, atomlist, defaultRadius var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - var mat = new THREE.MeshLambertMaterial({color: atom.color}); + var mat = new THREE.MeshLambertMaterial({color: atom.color, map:this.colormap}); var sphere = new THREE.Mesh(geo, mat); sphere.scale.x = sphere.scale.y = sphere.scale.z = (!forceDefault && this.vdwRadii[atom.elem] != undefined) ? this.vdwRadii[atom.elem] : defaultRadius; group.add(sphere); @@ -408,7 +461,7 @@ GLmol.prototype.drawBondsAsStick = function(group, atomlist, bondR, atomR, ignor this.drawCylinder(group, new TV3(atom2.x, atom2.y, atom2.z), mp, bondR, atom2.color); } if (!atom1.connected) continue; - var sphereMaterial = new THREE.MeshLambertMaterial({color: atom1.color}); + var sphereMaterial = new THREE.MeshLambertMaterial({color: atom1.color, map:this.colormap}); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); sphere.scale.x = sphere.scale.y = sphere.scale.z = atomR; group.add(sphere); @@ -449,7 +502,7 @@ GLmol.prototype.drawUnitcell = function(group) { for (var i = 0; i < edges.length; i++) { geo.vertices.push(new TV3(vertices[edges[i]][0], vertices[edges[i]][1], vertices[edges[i]][2])); } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: 1, color: 0xcccccc}); + var lineMaterial = new THREE.LineBasicMaterial({linewidth: 1, color: 0xcccccc}); // TODO: fix color var line = new THREE.Line(geo, lineMaterial); line.type = THREE.LinePieces; group.add(line); @@ -556,7 +609,8 @@ GLmol.prototype.drawBondsAsLine = function(group, atomlist, lineWidth) { } var lineMaterial = new THREE.LineBasicMaterial({linewidth: lineWidth}); lineMaterial.vertexColors = true; - + lineMaterial.map = this.colormap; + console.log(lineMaterial); var line = new THREE.Line(geo, lineMaterial); line.type = THREE.LinePieces; group.add(line); @@ -574,7 +628,7 @@ GLmol.prototype.drawSmoothCurve = function(group, _points, width, colors, div) { geo.vertices.push(points[i]); geo.colors.push(new TCo(colors[(i == 0) ? 0 : Math.round((i - 1) / div)])); } - var lineMaterial = new THREE.LineBasicMaterial({linewidth: width}); + var lineMaterial = new THREE.LineBasicMaterial({linewidth: width, map: this.colormap}); lineMaterial.vertexColors = true; var line = new THREE.Line(geo, lineMaterial); line.type = THREE.LineStrip; @@ -663,7 +717,7 @@ GLmol.prototype.drawSmoothTube = function(group, _points, colors, radii) { } geo.computeFaceNormals(); geo.computeVertexNormals(false); - var mat = new THREE.MeshLambertMaterial();// mat.wireframe = true; + var mat = new THREE.MeshLambertMaterial({map:this.colormap});// mat.wireframe = true; mat.vertexColors = THREE.FaceColors; var mesh = new THREE.Mesh(geo, mat); mesh.doubleSided = true; @@ -726,7 +780,7 @@ GLmol.prototype.drawStrip = function(group, p1, p2, colors, div, thickness) { div = div || this.axisDIV; p1 = this.subdivide(p1, div); p2 = this.subdivide(p2, div); - if (!thickness) this.drawThinStrip(group, p1, p2, colors, div) + if (!thickness) {this.drawThinStrip(group, p1, p2, colors, div); return;} var geo = new THREE.Geometry(); var vs = geo.vertices, fs = geo.faces; @@ -761,7 +815,7 @@ GLmol.prototype.drawStrip = function(group, p1, p2, colors, div, thickness) { fs.push(new THREE.Face4(vsize + 1, vsize + 5, vsize + 7, vsize + 3, undefined, fs[fs.length - 3].color)); geo.computeFaceNormals(); geo.computeVertexNormals(false); - var material = new THREE.MeshLambertMaterial(); + var material = new THREE.MeshLambertMaterial({map: this.colormap}); material.vertexColors = THREE.FaceColors; var mesh = new THREE.Mesh(geo, material); mesh.doubleSided = true; @@ -782,7 +836,7 @@ GLmol.prototype.drawThinStrip = function(group, p1, p2, colors, div) { } geo.computeFaceNormals(); geo.computeVertexNormals(false); - var material = new THREE.MeshLambertMaterial(); + var material = new THREE.MeshLambertMaterial({map:this.colormap}); material.vertexColors = THREE.FaceColors; var mesh = new THREE.Mesh(geo, material); mesh.doubleSided = true; @@ -806,7 +860,7 @@ GLmol.prototype.drawCylinder = function(group, from, to, radius, color, cap) { this.cylinderGeometry.faceUvs = []; this.faceVertexUvs = []; } - var cylinderMaterial = new THREE.MeshLambertMaterial({color: color.getHex()}); + var cylinderMaterial = new THREE.MeshLambertMaterial({color: color.getHex(), map:this.colormap}); var cylinder = new THREE.Mesh(this.cylinderGeometry, cylinderMaterial); cylinder.position = midpoint; cylinder.lookAt(from); @@ -952,7 +1006,7 @@ GLmol.prototype.drawNucleicAcidLadder = function(group, atomlist) { } this.drawNucleicAcidLadderSub(geo, lineGeo, currentComponent, color); geo.computeFaceNormals(); - var mat = new THREE.MeshLambertMaterial(); + var mat = new THREE.MeshLambertMaterial({map:this.colormap}); mat.vertexColors = THREE.VertexColors; var mesh = new THREE.Mesh(geo, mat); mesh.doubleSided = true; @@ -1257,7 +1311,7 @@ GLmol.prototype.colorByAtom = function(atomlist, colors) { var c = colors[atom.elem]; if (c == undefined) c = this.ElementColors[atom.elem]; if (c == undefined) c = this.defaultColor; - atom.color = c; + this.setColor(atom.serial, c); } }; @@ -1268,8 +1322,8 @@ GLmol.prototype.colorByStructure = function(atomlist, helixColor, sheetColor, co var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; if (!colorSidechains && (atom.atom != 'CA' || atom.hetflag)) continue; - if (atom.ss[0] == 's') atom.color = sheetColor; - else if (atom.ss[0] == 'h') atom.color = helixColor; + if (atom.ss[0] == 's') this.setColor(atom.serial, sheetColor); + else if (atom.ss[0] == 'h') this.setColor(atom.serial, helixColor); } }; @@ -1300,7 +1354,7 @@ GLmol.prototype.colorByBFactor = function(atomlist, colorSidechains) { color.setHSV(0.667, (mid - atom.b) / range, 1); else color.setHSV(0, (atom.b - mid) / range, 1); - atom.color = color.getHex(); + this.setColor(atom.serial, color.getHex()); } } }; @@ -1313,7 +1367,7 @@ GLmol.prototype.colorByChain = function(atomlist, colorSidechains) { if (colorSidechains || atom.atom == 'CA' || atom.atom == 'O3\'') { var color = new TCo(0); color.setHSV((atom.chain.charCodeAt(0)) % 15 / 15.0, 1, 0.9); - atom.color = color.getHex(); + this.setColor(atom.serial, color.getHex()); } } }; @@ -1323,7 +1377,7 @@ GLmol.prototype.colorByResidue = function(atomlist, residueColors) { var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; c = residueColors[atom.resn] - if (c != undefined) atom.color = c; + if (c != undefined) this.setColor(atom.serial, c); } }; @@ -1331,7 +1385,7 @@ GLmol.prototype.colorAtoms = function(atomlist, c) { for (var i in atomlist) { var atom = this.atoms[atomlist[i]]; if (atom == undefined) continue; - atom.color = c; + this.setColor(atom.serial, c); } }; @@ -1341,7 +1395,7 @@ GLmol.prototype.colorByPolarity = function(atomlist, polar, nonpolar) { var colorMap = {}; for (var i in polarResidues) colorMap[polarResidues[i]] = polar; for (i in nonPolarResidues) colorMap[nonPolarResidues[i]] = nonpolar; - this.colorByResidue(atomlist, colorMap); + this.colorByResidue(atomlist, colorMap); }; // TODO: Add near(atomlist, neighbor, distanceCutoff) @@ -1365,7 +1419,7 @@ GLmol.prototype.colorChainbow = function(atomlist, colorSidechains) { if ((colorSidechains || atom.atom != 'CA' || atom.atom != 'O3\'') && !atom.hetflag) { var color = new TCo(0); color.setHSV(240.0 / 360 * (1 - cnt / total), 1, 0.9); - atom.color = color.getHex(); + this.setColor(atom.serial, color.getHex()); cnt++; } } diff --git a/src/js/Three49custom.js b/src/js/Three49custom.js index 01abdec..76c13df 100644 --- a/src/js/Three49custom.js +++ b/src/js/Three49custom.js @@ -206,7 +206,7 @@ c.near;k.fogFar.value=c.far}else if(c instanceof THREE.FogExp2)k.fogDensity.valu j.color;p=j.intensity;s=j.distance;if(j instanceof THREE.AmbientLight)if(D.gammaInput){l=l+m.r*m.r;n=n+m.g*m.g;o=o+m.b*m.b}else{l=l+m.r;n=n+m.g;o=o+m.b}else if(j instanceof THREE.DirectionalLight){s=Z*3;if(D.gammaInput){y[s]=m.r*m.r*p*p;y[s+1]=m.g*m.g*p*p;y[s+2]=m.b*m.b*p*p}else{y[s]=m.r*p;y[s+1]=m.g*p;y[s+2]=m.b*p}Ca.copy(j.matrixWorld.getPosition());Ca.subSelf(j.target.matrixWorld.getPosition());Ca.normalize();A[s]=Ca.x;A[s+1]=Ca.y;A[s+2]=Ca.z;Z=Z+1}else if(j instanceof THREE.PointLight){la=I*3; if(D.gammaInput){B[la]=m.r*m.r*p*p;B[la+1]=m.g*m.g*p*p;B[la+2]=m.b*m.b*p*p}else{B[la]=m.r*p;B[la+1]=m.g*p;B[la+2]=m.b*p}m=j.matrixWorld.getPosition();K[la]=m.x;K[la+1]=m.y;K[la+2]=m.z;N[I]=s;I=I+1}else if(j instanceof THREE.SpotLight){la=R*3;if(D.gammaInput){Y[la]=m.r*m.r*p*p;Y[la+1]=m.g*m.g*p*p;Y[la+2]=m.b*m.b*p*p}else{Y[la]=m.r*p;Y[la+1]=m.g*p;Y[la+2]=m.b*p}m=j.matrixWorld.getPosition();O[la]=m.x;O[la+1]=m.y;O[la+2]=m.z;ba[R]=s;Ca.copy(m);Ca.subSelf(j.target.matrixWorld.getPosition());Ca.normalize(); ja[la]=Ca.x;ja[la+1]=Ca.y;ja[la+2]=Ca.z;ca[R]=Math.cos(j.angle);Q[R]=j.exponent;R=R+1}}}c=Z*3;for(i=y.length;c

About

GLmol -- Molecular Viewer on WebGL/Javascript
-Version 0.40 (20120429)

+Version 0.40+VTF (20120430)

This program is written by biochem_fan and released under LGPL. Please visit my project page for the details and source code distribution.

Comments and Suggestions are welcome. Please mail to biochem_fan at users.sourceforge.jp or write in the forum.

How to use

@@ -143,7 +143,15 @@

How to use

Translate
Zoom
Slab

- +
+ + + +
@@ -166,6 +174,7 @@

How to use

addTab('#glmol01_srcbox', '400px', 0); addTab('#glmol01_viewbox', '350px', 1); addTab('#glmol01_infobox', '400px', 2); +addTab('#glmol01_seqbox', '600px', 3); var glmol01 = new GLmol('glmol01', true); var query = window.location.search.substring(1); @@ -347,6 +356,42 @@

How to use

}; glmol01.defineRepresentation = defineRepFromController; +glmol01.loadMoleculeOld = glmol01.loadMolecule; + +glmol01.ResnTable = {ALA: 'A', CYS: 'C', ASP: 'D', GLU: 'E', PHE: 'F', GLY: 'G', HIS: 'H', ILE: 'I', LYS: 'K', LEU: 'L', MET: 'M', ASN: 'N', PRO: 'P', GLN: 'Q', ARG: 'R', SER: 'S', THR: 'T', VAL: 'V', TRP: 'W', TYR: 'Y', 'HOH': 'O'}; + +glmol01.loadMolecule = function() { + this.loadMoleculeOld(); + + var str = '
'; + var currentChain, currentResi, currentResn, currentResidues = []; + + for (var i = 0; i < 100000; i++) { + atom = this.atoms[i]; if (!atom) continue; + if (atom.resn == "HOH") continue; + + if (atom.chain != currentChain || atom.resi != currentResi) { + if (atom.chain != currentChain) { + str += "
Chain " + atom.chain + ": "; + } + if (currentResidues.length > 0) { + var resn = glmol01.ResnTable[currentResn]; + if (!resn) resn = " " + currentResn + " "; + str += '' + resn + ''; + } + currentResidues = []; + } + currentChain = atom.chain; + currentResn = atom.resn; + currentResi = atom.resi; + currentResidues.push(atom.serial); + } + + str += '
'; + $('#' + this.id + '_seq').html(str); + +}; +