OpenJsCad/viewer.js
Joost Nieuwenhuijse 4516cd57e7 First release!
2012-01-20 15:52:48 +01:00

193 lines
5 KiB
JavaScript

// Draw triangle lines:
Viewer.drawLines = false;
// Set to true so lines don't use the depth buffer
Viewer.lineOverlay = false;
// Set the color of all polygons in this solid
CSG.prototype.setColor = function(r, g, b) {
this.toPolygons().map(function(polygon) {
polygon.shared = [r, g, b];
});
};
// Convert from CSG solid to GL.Mesh object
CSG.prototype.toMesh = function() {
var csg = this.canonicalized();
var mesh = new GL.Mesh({ normals: true, colors: true });
var vertexTag2Index = {};
var vertices = [];
var colors = [];
var triangles = [];
// set to true if we want to use interpolated vertex normals
// this creates nice round spheres but does not represent the shape of
// the actual model
var smoothlighting = false;
var polygons = csg.toPolygons();
var numpolygons = polygons.length;
for(var polygonindex = 0; polygonindex < numpolygons; polygonindex++)
{
var polygon = polygons[polygonindex];
var indices = polygon.vertices.map(function(vertex) {
var vertextag = vertex.getTag();
var vertexindex;
if(smoothlighting && (vertextag in vertexTag2Index))
{
vertexindex = vertexTag2Index[vertextag];
}
else
{
vertexindex = vertices.length;
vertexTag2Index[vertextag] = vertexindex;
vertices.push([vertex.pos.x, vertex.pos.y, vertex.pos.z]);
colors.push([0,0,1]);
}
return vertexindex;
});
for (var i = 2; i < indices.length; i++) {
triangles.push([indices[0], indices[i - 1], indices[i]]);
}
}
mesh.triangles = triangles;
mesh.vertices = vertices;
mesh.colors = colors;
mesh.computeWireframe();
mesh.computeNormals();
return mesh;
};
var viewers = [];
// A viewer is a WebGL canvas that lets the user view a mesh. The user can
// tumble it around by dragging the mouse.
function Viewer(csg, width, height, depth) {
var angleX = 0;
var angleY = 0;
var viewpointX = 0;
var viewpointY = 0;
viewers.push(this);
// Get a new WebGL canvas
var gl = GL.create();
this.gl = gl;
this.mesh = csg.toMesh();
// Set up the viewport
gl.canvas.width = width;
gl.canvas.height = height;
gl.viewport(0, 0, width, height);
gl.matrixMode(gl.PROJECTION);
gl.loadIdentity();
gl.perspective(45, width / height, 0.1, 100);
gl.matrixMode(gl.MODELVIEW);
// Set up WebGL state
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.clearColor(0.93, 0.93, 0.93, 1);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.polygonOffset(1, 1);
// Black shader for wireframe
this.blackShader = new GL.Shader('\
void main() {\
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\
}\
', '\
void main() {\
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);\
}\
');
// Shader with diffuse and specular lighting
this.lightingShader = new GL.Shader('\
varying vec3 color;\
varying vec3 normal;\
varying vec3 light;\
void main() {\
const vec3 lightDir = vec3(1.0, 2.0, 3.0) / 3.741657386773941;\
light = lightDir;\
color = gl_Color.rgb;\
normal = gl_NormalMatrix * gl_Normal;\
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\
}\
', '\
varying vec3 color;\
varying vec3 normal;\
varying vec3 light;\
void main() {\
vec3 n = normalize(normal);\
float diffuse = max(0.0, dot(light, n));\
float specular = pow(max(0.0, -reflect(light, n).z), 10.0) * sqrt(diffuse);\
gl_FragColor = vec4(mix(color * (0.3 + 0.7 * diffuse), vec3(1.0), specular), 1.0);\
}\
');
var _this=this;
gl.onmousemove = function(e) {
if (e.dragging) {
e.preventDefault();
if(e.altKey)
{
var factor = 1e-2;
depth *= Math.pow(2,factor * e.deltaY);
}
else if(e.shiftKey)
{
var factor = 5e-3;
viewpointX += factor * e.deltaX * depth;
viewpointY -= factor * e.deltaY * depth;
}
else
{
angleY += e.deltaX * 2;
angleX += e.deltaY * 2;
angleX = Math.max(-90, Math.min(90, angleX));
}
_this.gl.ondraw();
}
};
gl.onmousewheel = function(e) {
e.preventDefault();
var delta = e.wheelDelta();
var factor = 1e-5;
depth *= Math.pow(factor * delta);
};
var that = this;
gl.ondraw = function() {
gl.makeCurrent();
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.loadIdentity();
gl.translate(viewpointX, viewpointY, -depth);
gl.rotate(angleX, 1, 0, 0);
gl.rotate(angleY, 0, 1, 0);
if (!Viewer.lineOverlay) gl.enable(gl.POLYGON_OFFSET_FILL);
that.lightingShader.draw(that.mesh, gl.TRIANGLES);
if (!Viewer.lineOverlay) gl.disable(gl.POLYGON_OFFSET_FILL);
if(Viewer.drawLines)
{
if (Viewer.lineOverlay) gl.disable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
that.blackShader.draw(that.mesh, gl.LINES);
gl.disable(gl.BLEND);
if (Viewer.lineOverlay) gl.enable(gl.DEPTH_TEST);
}
};
gl.ondraw();
}
var nextID = 0;
function addViewer(viewer) {
document.getElementById(nextID++).appendChild(viewer.gl.canvas);
}