diff --git a/demos/acorn/acorn.html b/demos/acorn/acorn.html
index 0982a56..b3b6e24 100644
--- a/demos/acorn/acorn.html
+++ b/demos/acorn/acorn.html
@@ -1,13 +1,11 @@
-
-
diff --git a/demos/mickey/mickey.html b/demos/mickey/mickey.html
index 03dec81..1e3f8ca 100644
--- a/demos/mickey/mickey.html
+++ b/demos/mickey/mickey.html
@@ -2,13 +2,31 @@
-
-
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+ A cross-browser JavaScript tool which will emulate Arius3D's PointStream viewer.
+ It will be able to quickly render a large amount of point cloud data to the <canvas >
+ tag using WebGL.
+
+
diff --git a/demos/mickey/mickey.js b/demos/mickey/mickey.js
index e28e851..cdd9781 100644
--- a/demos/mickey/mickey.js
+++ b/demos/mickey/mickey.js
@@ -10,7 +10,7 @@ var size = 500;
window.onresize = function(){
ps.resize(window.innerWidth, window.innerHeight);
- ps.background([0.3,0.5,0.7,1]);
+ ps.background([0.3,0.5,0.7,0.2]);
};
function zoom(amt){
@@ -59,7 +59,7 @@ function start(){
ps.setup(document.getElementById('canvas'), render);
ps.pointSize(8);
- ps.background([0.3,0.5,0.7,1]);
+ ps.background([0.3,0.5,0.7,0.2]);
ps.onMouseScroll = zoom;
ps.onMousePressed = mousePressed;
diff --git a/pointstream.js b/pointstream.js
index 93d4279..7762fa6 100644
--- a/pointstream.js
+++ b/pointstream.js
@@ -1,773 +1,12 @@
-/*
- Copyright (c) 2010 Seneca College
- MIT LICENSE
-
-TODO:
-- add mouseScroll empty var?
-- change verts, norms, cols to webglarrays?
-- should mousewheel return single value or object?
-- add external js loading so mjs isn't present in html file
-*/
-
-function PointStream(){
-
- const version = 0.2;
- const XHR_DONE = 4;
-
- // to calculate fps
- var frames = 0;
- var lastTime;
-
- var renderCallback;
-
- var bk = [1,1,1,1];
- var VBOs;
-
- // defaults
- var attn = [0.01, 0.0, 0.003];
-
- // browser detection to handle differences such as mouse scrolling
- var browser = -1 ;
- const MINEFIELD = 0;
- const CHROME = 1;
- const CHROMIUM = 2;
- const WEBKIT = 3;
-
- // not used yet
- const FIREFOX = 4;
- const OPERA = 5;
- const SAFARI = 6;
- const IE = 7;
-
- var verts = [];
- var cols = [];
- var norms = [];
-
- var canvas;
- var ctx;
-
- var bufferIDCounter = 0;
-
- // shader matrices
- var projection;
- var view;
- var model;
- var normalTransform;
-
- var progObj;
-
- // Vertex shader for boxes and spheres
- var vertexShaderSource =
- "attribute vec3 aVertex;" +
- "attribute vec3 aNormal;" +
- "attribute vec4 aColor;" +
-
- "uniform bool usingMat;" +
- "uniform vec3 specular;" +
- "uniform vec3 mat_emissive;" +
- "uniform vec3 mat_ambient;" +
- "uniform vec3 mat_specular;" +
- "uniform float shininess;" +
-
- //
- "uniform float pointSize;" +
- "uniform vec3 attenuation;" +
-
- "uniform mat4 model;" +
- "uniform mat4 view;" +
- "uniform mat4 projection;" +
- "uniform mat4 normalTransform;" +
-
- "uniform int lightCount;" +
-
- " uniform vec3 lposition;" +
- " uniform vec3 lcolor;" +
-
- "void DirectionalLight( inout vec3 col, in vec3 ecPos, in vec3 vertNormal ) {" +
- " float nDotVP = max(0.0, dot( vertNormal, lposition ));" +
- " float nDotVH = max(0.0, dot( vertNormal, normalize( lposition-ecPos )));" +
- " col += lcolor * 2.0 * nDotVP;" +
- "}" +
-
- "void PointLight( inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" +
- // " float powerfactor;" +
-
- // Get the vector from the light to the vertex
- " vec3 VP = lposition - ecPos;" +
-
- // Get the distance from the current vector to the light position
- " float d = length( VP ); " +
-
- // Normalize the light ray so it can be used in the dot product operation.
- " VP = normalize( VP );" +
-
- " float attenuation = 1.0 / ( 1.0 + ( d ) + ( d * d ));" +
-
- " float nDotVP = max( 0.0, dot( vertNormal, VP ));" +
- " vec3 halfVector = normalize( VP + eye );" +
- " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" +
-
- // " spec += specular * powerfactor * attenuation;" +
- " col += lcolor * nDotVP * 2.0;" +
- "}" +
-
- "void main(void) {" +
- " vec3 finalDiffuse = vec3( 0.0, 0.0, 0.0 );" +
-
- " vec4 col = aColor;" +
-
- " vec3 norm = vec3( normalTransform * vec4( aNormal, 0.0 ) );" +
-
- " vec4 ecPos4 = view * model * vec4(aVertex,1.0);" +
- " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
- " vec3 eye = vec3( 0.0, 0.0, 1.0 );" +
-
- // If there were no lights this draw call, just use the
- // assigned fill color of the shape and the specular value
- " if( lightCount == 0 ) {" +
- " gl_FrontColor = vec4(col[0], col[1], col[2], 1.0);" +
- " }" +
- " else {" +
- " PointLight(finalDiffuse, ecPos, norm, eye );" +
- " gl_FrontColor = vec4(finalDiffuse[0] * col[0], finalDiffuse[1] * col[1], finalDiffuse[2] * col[2], 1.0);" +
- " }" +
-
- " float dist = length( view * model * vec4(aVertex, 1.0));" +
- "float attn = attenuation[0] + (attenuation[1] * dist) + (attenuation[2] * dist * dist);" +
-
- " if(attn > 0.0){" +
- " gl_PointSize = pointSize * sqrt(1.0/attn);" +
- " }" +
- " else{" +
- " gl_PointSize = 1.0;" +
- " }"+
-
- " gl_Position = projection * view * model * vec4(aVertex, 1.0);" +
- "}";
-
- var fragmentShaderSource =
- "void main(void){" +
- " gl_FragColor = gl_Color;" +
- "}";
-
- /**
- */
- function uniformi(programObj, varName, varValue) {
- var varLocation = ctx.getUniformLocation(programObj, varName);
- // the variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- if (varValue.length === 4) {
- ctx.uniform4iv(varLocation, varValue);
- } else if (varValue.length === 3) {
- ctx.uniform3iv(varLocation, varValue);
- } else if (varValue.length === 2) {
- ctx.uniform2iv(varLocation, varValue);
- } else {
- ctx.uniform1i(varLocation, varValue);
- }
- }
- }
-
- /**
- */
- function uniformf(programObj, varName, varValue) {
- var varLocation = ctx.getUniformLocation(programObj, varName);
- // the variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- if (varValue.length === 4) {
- ctx.uniform4fv(varLocation, varValue);
- } else if (varValue.length === 3) {
- ctx.uniform3fv(varLocation, varValue);
- } else if (varValue.length === 2) {
- ctx.uniform2fv(varLocation, varValue);
- } else {
- ctx.uniform1f(varLocation, varValue);
- }
- }
- }
-
- /**
- */
- function vertexAttribPointer(programObj, varName, size, VBO) {
- var varLocation = ctx.getAttribLocation(programObj, varName);
- if (varLocation !== -1) {
- ctx.bindBuffer(ctx.ARRAY_BUFFER, VBO);
- ctx.vertexAttribPointer(varLocation, size, ctx.FLOAT, false, 0, 0);
- ctx.enableVertexAttribArray(varLocation);
- }
- }
-
- /**
- */
- function getDataLayout(values){
- var normalsPresent = false;
- var colorsPresent = false;
-
- // first check if there are 9 values, which would mean we have
- // xyz rgb and normals
-
- // We can do this by counting the number of whitespace on the first line
- var i = 0;
- var numSpaces = 0;
- do{
- i++;
- if(values[i] == " "){
- numSpaces++;
- }
- }while( values[i] != '\n');
-
- // 1.916 -2.421 -4.0339 64 32 16 -0.3727 -0.2476 -0.8942
- if(numSpaces === 8){
- return 9;
- }
-
- // 1.916 -2.421 -4.0339
- if(numSpaces == 2){
- return 3;
- }
-
- var str = "";
-
- for(i = 0; i < 500; i++){
- str += values[i];
- }
-
- var str_split = str.split(/\s+/);
- var data = [];
-
- for(var i=3; i < str_split.length;){
- data.push(str_split[i++]);
- data.push(str_split[i++]);
- data.push(str_split[i++]);
- i+=3;
- }
-
- for(var i=0; i < data.length; i++){
- if(data[i] < 0 || data[i] > 255){
- normalsPresent = true;
- return 1;
- }
- }
-
- return 2;
- }
-
- /**
- */
- function createVBOs(xyz, rgb, norm){
- if(ctx){
- var o = {};
-
- var newBuffer = ctx.createBuffer();
- ctx.bindBuffer(ctx.ARRAY_BUFFER, newBuffer);
- ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(xyz), ctx.STATIC_DRAW);
- o.posBuffer = newBuffer;
- o.id = bufferIDCounter;
- o.size = xyz.length;
-
- if(rgb.length > 0){
- var newColBuffer = ctx.createBuffer();
- ctx.bindBuffer(ctx.ARRAY_BUFFER, newColBuffer);
- ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(rgb), ctx.STATIC_DRAW);
- o.colBuffer = newColBuffer;
- }
-
- if(norm.length > 0){
- var newNormBuffer = ctx.createBuffer();
- ctx.bindBuffer(ctx.ARRAY_BUFFER, newNormBuffer);
- ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(norm), ctx.STATIC_DRAW);
- o.normBuffer = newNormBuffer;
- }
-
- bufferIDCounter++;
-
- return o;
- }
- };
-
- /**
- */
- function disableVertexAttribPointer(programObj, varName){
- var varLocation = ctx.getAttribLocation(programObj, varName);
- if (varLocation !== -1) {
- ctx.disableVertexAttribArray(varLocation);
- }
- }
-
- /**
- */
- function getUserAgent(userAgentString){
-
- // keep in this order
- if(userAgentString.match(/Chrome/)){
- return CHROME;
- }
- if(userAgentString.match(/AppleWebKit/)){
- return WEBKIT;
- }
- if(userAgentString.match(/Minefield/)){
- return MINEFIELD;
- }
- }
-
- /**
- */
- function uniformMatrix(programObj, varName, transpose, matrix) {
- var varLocation = ctx.getUniformLocation(programObj, varName);
- // the variable won't be found if it was optimized out.
- if (varLocation !== -1) {
- if (matrix.length === 16) {
- ctx.uniformMatrix4fv(varLocation, transpose, matrix);
- } else if (matrix.length === 9) {
- ctx.uniformMatrix3fv(varLocation, transpose, matrix);
- } else {
- ctx.uniformMatrix2fv(varLocation, transpose, matrix);
- }
- }
- }
-
- /**
- */
- var createProgramObject = function(ctx, vetexShaderSource, fragmentShaderSource) {
- var vertexShaderObject = ctx.createShader(ctx.VERTEX_SHADER);
- ctx.shaderSource(vertexShaderObject, vetexShaderSource);
- ctx.compileShader(vertexShaderObject);
- if (!ctx.getShaderParameter(vertexShaderObject, ctx.COMPILE_STATUS)) {
- throw ctx.getShaderInfoLog(vertexShaderObject);
- }
-
- var fragmentShaderObject = ctx.createShader(ctx.FRAGMENT_SHADER);
- ctx.shaderSource(fragmentShaderObject, fragmentShaderSource);
- ctx.compileShader(fragmentShaderObject);
- if (!ctx.getShaderParameter(fragmentShaderObject, ctx.COMPILE_STATUS)) {
- throw ctx.getShaderInfoLog(fragmentShaderObject);
- }
-
- var programObject = ctx.createProgram();
- ctx.attachShader(programObject, vertexShaderObject);
- ctx.attachShader(programObject, fragmentShaderObject);
- ctx.linkProgram(programObject);
- if (!ctx.getProgramParameter(programObject, ctx.LINK_STATUS)) {
- throw "Error linking shaders.";
- }
-
- return programObject;
- };
-
- /**
- */
- var xb = {
-
- /**
- */
- mouseX: 0,
- mouseY: 0,
-
- // Number of frames per seconds rendered in the last second.
- frameRate: 0,
-
- // Number of frames rendered since script started running
- frameCount: 0,
-
- /**
- color
- */
- background: function(color){
- ctx.clearColor(color[0],color[1],color[2],color[3]);
- },
-
- /**
- */
- clear: function(){
- ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT);
- },
-
- /**
- Get the version of the library.
- */
- getVersion: function(){
- return version;
- },
-
- /**
- Resize the viewport.
- This can be called after setup
-
- width
- height
- */
- resize: function(width, height){
- // delete old program object?
- // delete old context?
-
- canvas.setAttribute("width", width);
- canvas.setAttribute("height", height);
-
- // check if style exists? how? can't just query it...
- canvas.style.width = width;
- canvas.style.height = height;
-
- ctx = canvas.getContext("experimental-webgl");
- ctx.viewport(0, 0, width, height);
- ctx.enable(ctx.DEPTH_TEST);
-
- xb.background(bk);
-
- progObj = createProgramObject(ctx, vertexShaderSource, fragmentShaderSource);
- ctx.useProgram(progObj);
-
- var fovy = 60;
- var aspect = width/height;
- var znear = 0.001;
- var zfar = 1000;
-
- var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
- var ymin = -ymax;
- var xmin = ymin * aspect;
- var xmax = ymax * aspect;
-
- var left = xmin;
- var right = xmax;
- var top = ymax;
- var bottom = ymin;
-
- var X = 2 * znear / (right - left);
- var Y = 2 * znear / (top - bottom);
- var A = (right + left) / (right - left);
- var B = (top + bottom) / (top - bottom);
- var C = -(zfar + znear) / (zfar - znear);
- var D = -2 * zfar * znear / (zfar - znear);
-
- projection = M4x4.$(
- X, 0, A, 0,
- 0, Y, B, 0,
- 0, 0, C, D,
- 0, 0, -1, 0);
-
- view = M4x4.$(1,0,0,0,0,1,0,0,0,0,1, 0, 0,0,0,1);
- model = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
- normalTransform = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
-
- // if VBOs already exist, recreate them
- if(VBOs) {
- VBOs = createVBOs(verts, cols, norms);
-
-
- if(cols.length > 0){
- uniformf(progObj, "lcolor", [1,1,1]);
- uniformf(progObj, "lposition", [0,0,-1]);
- uniformi(progObj, "lightCount", 1);
- }
- }
-
- uniformf(progObj, "pointSize", 1);
- uniformf(progObj, "attenuation", [attn[0], attn[1], attn[2]]);
-
- uniformMatrix(progObj, "view", false, M4x4.transpose(view));
- uniformMatrix(progObj, "projection", false, M4x4.transpose(projection));
- },
-
- /**
- */
- render: function(){
-
- frames++;
- xb.frameCount++;
- var now = new Date();
-
- if(ctx && VBOs){
- vertexAttribPointer(progObj, "aVertex", 3, VBOs.posBuffer);
-
- if(VBOs.colBuffer){
- vertexAttribPointer(progObj, "aColor", 3, VBOs.colBuffer);
- }
- else{
- disableVertexAttribPointer(progObj, "aColor");
- }
-
- if(VBOs.normBuffer){
- vertexAttribPointer(progObj, "aNormal", 3, VBOs.normBuffer);
-
- uniformf(progObj, "lcolor", [1,1,1]);
- uniformf(progObj, "lposition", [0,0,-1]);
- uniformi(progObj, "lightCount", 1);
- }
- else{
- disableVertexAttribPointer(progObj, "aNormal");
- }
-
- var mvm = M4x4.mul(view, model);
- normalTransform = M4x4.inverseOrthonormal(mvm);
- uniformMatrix(progObj, "normalTransform", false, M4x4.transpose(normalTransform));
-
- uniformMatrix(progObj, "model", false, model);
-
- ctx.drawArrays(ctx.POINTS, 0, VBOs.size/3);
- }
-
- // if more than 1 second has elapsed, recalculate fps
- if(now - lastTime > 1000){
- xb.frameRate = frames/(now-lastTime)*1000;
- frames = 0;
- lastTime = now;
- }
-
- // clear state
- model = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
- },
-
- /**
- Update the cursor position everytime the mouse moves
- */
- mouseMove: function(e){
- xb.mouseX = e.pageX;
- xb.mouseY = e.pageY;
- },
-
- /**
- element
- type
- func
- */
- attach: function(element, type, func){
- //
- if(element.addEventListener){
- element.addEventListener(type, func, false);
- }
- },
-
- /*
- returns -1 or 1
- scrolling towards user is 1
- scrolling towards screen is -1
- should this return an object or a single value?
- */
- _mouseScroll: function(evt){
- var delta = 0;
-
- // which check to use?
- //if(browser === MINEFIELD){
- if(evt.detail){
- delta = evt.detail / 3;
- }
- else if(evt.wheelDelta){
- delta = -evt.wheelDelta / 360;
- }
-
- if(xb.onMouseScroll){
- xb.onMouseScroll(delta);
- }
- },
-
- _mousePressed: function(evt){
- if(xb.onMousePressed){
- xb.onMousePressed();
- }
- },
-
- _mouseReleased: function(){
- if(xb.onMouseReleased){
- xb.onMouseReleased();
- }
- },
-
- /**
- cvs
- renderCB
- */
- setup: function(cvs, renderCB){
- canvas = cvs;
- browser = getUserAgent(navigator.userAgent);
-
- lastTime = new Date();
- frames = 0;
-
- xb.resize(canvas.getAttribute("width"), canvas.getAttribute("height"));
-
- xb.renderCallback = renderCB;
- setInterval(xb.renderCallback, 10);
-
- xb.attach(cvs, "mouseup", xb._mouseReleased);
- xb.attach(cvs, "mousedown", xb._mousePressed);
- xb.attach(cvs, "mousemove", xb.mouseMove);
- xb.attach(cvs, "DOMMouseScroll", xb._mouseScroll);
- xb.attach(cvs, "mousewheel", xb._mouseScroll);
- },
-
- /**
- 1 arg = uniform scaling
- 3 args = independant scaling
- */
- scale: function(sx, sy, sz){
-
- // uniform scaling
- if( !sy && !sz){
- model = M4x4.scale1(sx, model);
- }
- else{
- model = M4x4.scale3(sx, sy, sz, model);
- }
- },
-
- /**
- tx
- ty
- tz
- */
- translate: function(tx, ty, tz){
- model = M4x4.translate3(tx, ty, tz, model, model);
- },
-
- /**
- radians
- */
- rotateY: function(radians){
- model = M4x4.rotate(radians,V3.$(0,1,0),model);
- },
-
- /**
- constant
- linear
- quadratic
- */
- attenuation: function(constant, linear, quadratic){
- uniformf(progObj, "attenuation", [constant, linear, quadratic]);
- },
-
- /**
- size - in pixels
- */
- pointSize: function(size){
- uniformf(progObj, "pointSize", size);
- },
-
- /**
- radians
- */
- rotateX: function(radians){
- model = M4x4.rotate(radians,V3.$(1,0,0),model);
- },
-
- /**
- radians
- */
- rotateZ: function(radians){
- model = M4x4.rotate(radians,V3.$(0,0,1),model);
- },
-
- /**
- o - object such as {path:"acorn.asc", autoCenter: true}
- */
- loadFile: function(o){
- var path = o.path;
-
- // need ||?
- var autoCenter = o.autoCenter || false;
-
- var AJAX = new XMLHttpRequest();
-
- // this doesn't work
- // AJAX.addEventListener("progress", f,false);
-
- AJAX.open("GET", path, true);
- AJAX.send(null);
-
- var file = {
- status: 0,
- progress: 0,
- numPoints: 0,
- };
-
- AJAX.onreadystatechange =
- function(){
- //??
- if(AJAX.status === 200){
- file.status = 1;
- }
-
- if(AJAX.readyState === XHR_DONE){
-
- var code = getDataLayout(AJAX.responseText);
-
- var normalsPresent = false;
- var colorsPresent = false;
-
- if(code == 1 ){
- code = 6;
- normalsPresent = true;
- }
- else if(code ==2 ){
- code = 6;
- colorsPresent = true;
- }
- if(code ==9){
- normalsPresent = true;
- colorsPresent = true;
-
- }
-
- var values = AJAX.responseText.split(/\s+/);
-
- const numVerts = values.length/code;
-
- var objCenter = [0,0,0];
-
- // xyz rgb normals
- for(var i = 0, len = values.length; i < len; i += code){
- var currX = parseFloat(values[i]);
- var currY = parseFloat(values[i+1]);
- var currZ = parseFloat(values[i+2]);
-
- verts.push(currX);
- verts.push(currY);
- verts.push(currZ);
-
- // don't waste cycles if the user didn't want it centered.
- if(autoCenter){
- objCenter[0] += currX;
- objCenter[1] += currY;
- objCenter[2] += currZ;
- }
-
- if(colorsPresent){
- cols.push(parseInt(values[i+3])/255);
- cols.push(parseInt(values[i+4])/255);
- cols.push(parseInt(values[i+5])/255);
- }
-
- if(normalsPresent){
- norms.push(parseFloat(values[i+6]));
- norms.push(parseFloat(values[i+7]));
- norms.push(parseFloat(values[i+8]));
- }
- }
-
- // if the user wants to center the point cloud
- if(autoCenter){
- objCenter[0] /= numVerts;
- objCenter[1] /= numVerts;
- objCenter[2] /= numVerts;
- }
-
- // if the user wanted to autocenter the point cloud,
- // iterate over all the verts and subtract by the
- // point cloud's current center.
- if(autoCenter){
- for(var i = 0; i < numVerts; i++){
- verts[i*3] -= objCenter[0];
- verts[i*3+1] -= objCenter[1];
- verts[i*3+2] -= objCenter[2];
- }
- }
-
- VBOs = createVBOs(verts, cols, norms);
-
- file.status = 4;
- }
- }
- return file;
- }
-
- }
- return xb;
-};
+var ps_include = function(path){
+ var lastScript = document.getElementsByTagName("head")[0].lastChild;
+ var fullUrl = lastScript.src.substring(0, lastScript.src.lastIndexOf('/') + 1) + path;
+ document.write('<' + 'script');
+ document.write(' language="javascript"');
+ document.write(' type="text/javascript"');
+ document.write(' src="' + fullUrl + '">');
+ document.write('' + 'script' + '>');
+}
+
+ps_include('mjs.js');
+ps_include('psapi.js');
diff --git a/psapi.js b/psapi.js
new file mode 100644
index 0000000..93d4279
--- /dev/null
+++ b/psapi.js
@@ -0,0 +1,773 @@
+/*
+ Copyright (c) 2010 Seneca College
+ MIT LICENSE
+
+TODO:
+- add mouseScroll empty var?
+- change verts, norms, cols to webglarrays?
+- should mousewheel return single value or object?
+- add external js loading so mjs isn't present in html file
+*/
+
+function PointStream(){
+
+ const version = 0.2;
+ const XHR_DONE = 4;
+
+ // to calculate fps
+ var frames = 0;
+ var lastTime;
+
+ var renderCallback;
+
+ var bk = [1,1,1,1];
+ var VBOs;
+
+ // defaults
+ var attn = [0.01, 0.0, 0.003];
+
+ // browser detection to handle differences such as mouse scrolling
+ var browser = -1 ;
+ const MINEFIELD = 0;
+ const CHROME = 1;
+ const CHROMIUM = 2;
+ const WEBKIT = 3;
+
+ // not used yet
+ const FIREFOX = 4;
+ const OPERA = 5;
+ const SAFARI = 6;
+ const IE = 7;
+
+ var verts = [];
+ var cols = [];
+ var norms = [];
+
+ var canvas;
+ var ctx;
+
+ var bufferIDCounter = 0;
+
+ // shader matrices
+ var projection;
+ var view;
+ var model;
+ var normalTransform;
+
+ var progObj;
+
+ // Vertex shader for boxes and spheres
+ var vertexShaderSource =
+ "attribute vec3 aVertex;" +
+ "attribute vec3 aNormal;" +
+ "attribute vec4 aColor;" +
+
+ "uniform bool usingMat;" +
+ "uniform vec3 specular;" +
+ "uniform vec3 mat_emissive;" +
+ "uniform vec3 mat_ambient;" +
+ "uniform vec3 mat_specular;" +
+ "uniform float shininess;" +
+
+ //
+ "uniform float pointSize;" +
+ "uniform vec3 attenuation;" +
+
+ "uniform mat4 model;" +
+ "uniform mat4 view;" +
+ "uniform mat4 projection;" +
+ "uniform mat4 normalTransform;" +
+
+ "uniform int lightCount;" +
+
+ " uniform vec3 lposition;" +
+ " uniform vec3 lcolor;" +
+
+ "void DirectionalLight( inout vec3 col, in vec3 ecPos, in vec3 vertNormal ) {" +
+ " float nDotVP = max(0.0, dot( vertNormal, lposition ));" +
+ " float nDotVH = max(0.0, dot( vertNormal, normalize( lposition-ecPos )));" +
+ " col += lcolor * 2.0 * nDotVP;" +
+ "}" +
+
+ "void PointLight( inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" +
+ // " float powerfactor;" +
+
+ // Get the vector from the light to the vertex
+ " vec3 VP = lposition - ecPos;" +
+
+ // Get the distance from the current vector to the light position
+ " float d = length( VP ); " +
+
+ // Normalize the light ray so it can be used in the dot product operation.
+ " VP = normalize( VP );" +
+
+ " float attenuation = 1.0 / ( 1.0 + ( d ) + ( d * d ));" +
+
+ " float nDotVP = max( 0.0, dot( vertNormal, VP ));" +
+ " vec3 halfVector = normalize( VP + eye );" +
+ " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" +
+
+ // " spec += specular * powerfactor * attenuation;" +
+ " col += lcolor * nDotVP * 2.0;" +
+ "}" +
+
+ "void main(void) {" +
+ " vec3 finalDiffuse = vec3( 0.0, 0.0, 0.0 );" +
+
+ " vec4 col = aColor;" +
+
+ " vec3 norm = vec3( normalTransform * vec4( aNormal, 0.0 ) );" +
+
+ " vec4 ecPos4 = view * model * vec4(aVertex,1.0);" +
+ " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
+ " vec3 eye = vec3( 0.0, 0.0, 1.0 );" +
+
+ // If there were no lights this draw call, just use the
+ // assigned fill color of the shape and the specular value
+ " if( lightCount == 0 ) {" +
+ " gl_FrontColor = vec4(col[0], col[1], col[2], 1.0);" +
+ " }" +
+ " else {" +
+ " PointLight(finalDiffuse, ecPos, norm, eye );" +
+ " gl_FrontColor = vec4(finalDiffuse[0] * col[0], finalDiffuse[1] * col[1], finalDiffuse[2] * col[2], 1.0);" +
+ " }" +
+
+ " float dist = length( view * model * vec4(aVertex, 1.0));" +
+ "float attn = attenuation[0] + (attenuation[1] * dist) + (attenuation[2] * dist * dist);" +
+
+ " if(attn > 0.0){" +
+ " gl_PointSize = pointSize * sqrt(1.0/attn);" +
+ " }" +
+ " else{" +
+ " gl_PointSize = 1.0;" +
+ " }"+
+
+ " gl_Position = projection * view * model * vec4(aVertex, 1.0);" +
+ "}";
+
+ var fragmentShaderSource =
+ "void main(void){" +
+ " gl_FragColor = gl_Color;" +
+ "}";
+
+ /**
+ */
+ function uniformi(programObj, varName, varValue) {
+ var varLocation = ctx.getUniformLocation(programObj, varName);
+ // the variable won't be found if it was optimized out.
+ if (varLocation !== -1) {
+ if (varValue.length === 4) {
+ ctx.uniform4iv(varLocation, varValue);
+ } else if (varValue.length === 3) {
+ ctx.uniform3iv(varLocation, varValue);
+ } else if (varValue.length === 2) {
+ ctx.uniform2iv(varLocation, varValue);
+ } else {
+ ctx.uniform1i(varLocation, varValue);
+ }
+ }
+ }
+
+ /**
+ */
+ function uniformf(programObj, varName, varValue) {
+ var varLocation = ctx.getUniformLocation(programObj, varName);
+ // the variable won't be found if it was optimized out.
+ if (varLocation !== -1) {
+ if (varValue.length === 4) {
+ ctx.uniform4fv(varLocation, varValue);
+ } else if (varValue.length === 3) {
+ ctx.uniform3fv(varLocation, varValue);
+ } else if (varValue.length === 2) {
+ ctx.uniform2fv(varLocation, varValue);
+ } else {
+ ctx.uniform1f(varLocation, varValue);
+ }
+ }
+ }
+
+ /**
+ */
+ function vertexAttribPointer(programObj, varName, size, VBO) {
+ var varLocation = ctx.getAttribLocation(programObj, varName);
+ if (varLocation !== -1) {
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, VBO);
+ ctx.vertexAttribPointer(varLocation, size, ctx.FLOAT, false, 0, 0);
+ ctx.enableVertexAttribArray(varLocation);
+ }
+ }
+
+ /**
+ */
+ function getDataLayout(values){
+ var normalsPresent = false;
+ var colorsPresent = false;
+
+ // first check if there are 9 values, which would mean we have
+ // xyz rgb and normals
+
+ // We can do this by counting the number of whitespace on the first line
+ var i = 0;
+ var numSpaces = 0;
+ do{
+ i++;
+ if(values[i] == " "){
+ numSpaces++;
+ }
+ }while( values[i] != '\n');
+
+ // 1.916 -2.421 -4.0339 64 32 16 -0.3727 -0.2476 -0.8942
+ if(numSpaces === 8){
+ return 9;
+ }
+
+ // 1.916 -2.421 -4.0339
+ if(numSpaces == 2){
+ return 3;
+ }
+
+ var str = "";
+
+ for(i = 0; i < 500; i++){
+ str += values[i];
+ }
+
+ var str_split = str.split(/\s+/);
+ var data = [];
+
+ for(var i=3; i < str_split.length;){
+ data.push(str_split[i++]);
+ data.push(str_split[i++]);
+ data.push(str_split[i++]);
+ i+=3;
+ }
+
+ for(var i=0; i < data.length; i++){
+ if(data[i] < 0 || data[i] > 255){
+ normalsPresent = true;
+ return 1;
+ }
+ }
+
+ return 2;
+ }
+
+ /**
+ */
+ function createVBOs(xyz, rgb, norm){
+ if(ctx){
+ var o = {};
+
+ var newBuffer = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, newBuffer);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(xyz), ctx.STATIC_DRAW);
+ o.posBuffer = newBuffer;
+ o.id = bufferIDCounter;
+ o.size = xyz.length;
+
+ if(rgb.length > 0){
+ var newColBuffer = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, newColBuffer);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(rgb), ctx.STATIC_DRAW);
+ o.colBuffer = newColBuffer;
+ }
+
+ if(norm.length > 0){
+ var newNormBuffer = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, newNormBuffer);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(norm), ctx.STATIC_DRAW);
+ o.normBuffer = newNormBuffer;
+ }
+
+ bufferIDCounter++;
+
+ return o;
+ }
+ };
+
+ /**
+ */
+ function disableVertexAttribPointer(programObj, varName){
+ var varLocation = ctx.getAttribLocation(programObj, varName);
+ if (varLocation !== -1) {
+ ctx.disableVertexAttribArray(varLocation);
+ }
+ }
+
+ /**
+ */
+ function getUserAgent(userAgentString){
+
+ // keep in this order
+ if(userAgentString.match(/Chrome/)){
+ return CHROME;
+ }
+ if(userAgentString.match(/AppleWebKit/)){
+ return WEBKIT;
+ }
+ if(userAgentString.match(/Minefield/)){
+ return MINEFIELD;
+ }
+ }
+
+ /**
+ */
+ function uniformMatrix(programObj, varName, transpose, matrix) {
+ var varLocation = ctx.getUniformLocation(programObj, varName);
+ // the variable won't be found if it was optimized out.
+ if (varLocation !== -1) {
+ if (matrix.length === 16) {
+ ctx.uniformMatrix4fv(varLocation, transpose, matrix);
+ } else if (matrix.length === 9) {
+ ctx.uniformMatrix3fv(varLocation, transpose, matrix);
+ } else {
+ ctx.uniformMatrix2fv(varLocation, transpose, matrix);
+ }
+ }
+ }
+
+ /**
+ */
+ var createProgramObject = function(ctx, vetexShaderSource, fragmentShaderSource) {
+ var vertexShaderObject = ctx.createShader(ctx.VERTEX_SHADER);
+ ctx.shaderSource(vertexShaderObject, vetexShaderSource);
+ ctx.compileShader(vertexShaderObject);
+ if (!ctx.getShaderParameter(vertexShaderObject, ctx.COMPILE_STATUS)) {
+ throw ctx.getShaderInfoLog(vertexShaderObject);
+ }
+
+ var fragmentShaderObject = ctx.createShader(ctx.FRAGMENT_SHADER);
+ ctx.shaderSource(fragmentShaderObject, fragmentShaderSource);
+ ctx.compileShader(fragmentShaderObject);
+ if (!ctx.getShaderParameter(fragmentShaderObject, ctx.COMPILE_STATUS)) {
+ throw ctx.getShaderInfoLog(fragmentShaderObject);
+ }
+
+ var programObject = ctx.createProgram();
+ ctx.attachShader(programObject, vertexShaderObject);
+ ctx.attachShader(programObject, fragmentShaderObject);
+ ctx.linkProgram(programObject);
+ if (!ctx.getProgramParameter(programObject, ctx.LINK_STATUS)) {
+ throw "Error linking shaders.";
+ }
+
+ return programObject;
+ };
+
+ /**
+ */
+ var xb = {
+
+ /**
+ */
+ mouseX: 0,
+ mouseY: 0,
+
+ // Number of frames per seconds rendered in the last second.
+ frameRate: 0,
+
+ // Number of frames rendered since script started running
+ frameCount: 0,
+
+ /**
+ color
+ */
+ background: function(color){
+ ctx.clearColor(color[0],color[1],color[2],color[3]);
+ },
+
+ /**
+ */
+ clear: function(){
+ ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT);
+ },
+
+ /**
+ Get the version of the library.
+ */
+ getVersion: function(){
+ return version;
+ },
+
+ /**
+ Resize the viewport.
+ This can be called after setup
+
+ width
+ height
+ */
+ resize: function(width, height){
+ // delete old program object?
+ // delete old context?
+
+ canvas.setAttribute("width", width);
+ canvas.setAttribute("height", height);
+
+ // check if style exists? how? can't just query it...
+ canvas.style.width = width;
+ canvas.style.height = height;
+
+ ctx = canvas.getContext("experimental-webgl");
+ ctx.viewport(0, 0, width, height);
+ ctx.enable(ctx.DEPTH_TEST);
+
+ xb.background(bk);
+
+ progObj = createProgramObject(ctx, vertexShaderSource, fragmentShaderSource);
+ ctx.useProgram(progObj);
+
+ var fovy = 60;
+ var aspect = width/height;
+ var znear = 0.001;
+ var zfar = 1000;
+
+ var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
+ var ymin = -ymax;
+ var xmin = ymin * aspect;
+ var xmax = ymax * aspect;
+
+ var left = xmin;
+ var right = xmax;
+ var top = ymax;
+ var bottom = ymin;
+
+ var X = 2 * znear / (right - left);
+ var Y = 2 * znear / (top - bottom);
+ var A = (right + left) / (right - left);
+ var B = (top + bottom) / (top - bottom);
+ var C = -(zfar + znear) / (zfar - znear);
+ var D = -2 * zfar * znear / (zfar - znear);
+
+ projection = M4x4.$(
+ X, 0, A, 0,
+ 0, Y, B, 0,
+ 0, 0, C, D,
+ 0, 0, -1, 0);
+
+ view = M4x4.$(1,0,0,0,0,1,0,0,0,0,1, 0, 0,0,0,1);
+ model = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
+ normalTransform = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
+
+ // if VBOs already exist, recreate them
+ if(VBOs) {
+ VBOs = createVBOs(verts, cols, norms);
+
+
+ if(cols.length > 0){
+ uniformf(progObj, "lcolor", [1,1,1]);
+ uniformf(progObj, "lposition", [0,0,-1]);
+ uniformi(progObj, "lightCount", 1);
+ }
+ }
+
+ uniformf(progObj, "pointSize", 1);
+ uniformf(progObj, "attenuation", [attn[0], attn[1], attn[2]]);
+
+ uniformMatrix(progObj, "view", false, M4x4.transpose(view));
+ uniformMatrix(progObj, "projection", false, M4x4.transpose(projection));
+ },
+
+ /**
+ */
+ render: function(){
+
+ frames++;
+ xb.frameCount++;
+ var now = new Date();
+
+ if(ctx && VBOs){
+ vertexAttribPointer(progObj, "aVertex", 3, VBOs.posBuffer);
+
+ if(VBOs.colBuffer){
+ vertexAttribPointer(progObj, "aColor", 3, VBOs.colBuffer);
+ }
+ else{
+ disableVertexAttribPointer(progObj, "aColor");
+ }
+
+ if(VBOs.normBuffer){
+ vertexAttribPointer(progObj, "aNormal", 3, VBOs.normBuffer);
+
+ uniformf(progObj, "lcolor", [1,1,1]);
+ uniformf(progObj, "lposition", [0,0,-1]);
+ uniformi(progObj, "lightCount", 1);
+ }
+ else{
+ disableVertexAttribPointer(progObj, "aNormal");
+ }
+
+ var mvm = M4x4.mul(view, model);
+ normalTransform = M4x4.inverseOrthonormal(mvm);
+ uniformMatrix(progObj, "normalTransform", false, M4x4.transpose(normalTransform));
+
+ uniformMatrix(progObj, "model", false, model);
+
+ ctx.drawArrays(ctx.POINTS, 0, VBOs.size/3);
+ }
+
+ // if more than 1 second has elapsed, recalculate fps
+ if(now - lastTime > 1000){
+ xb.frameRate = frames/(now-lastTime)*1000;
+ frames = 0;
+ lastTime = now;
+ }
+
+ // clear state
+ model = M4x4.$(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
+ },
+
+ /**
+ Update the cursor position everytime the mouse moves
+ */
+ mouseMove: function(e){
+ xb.mouseX = e.pageX;
+ xb.mouseY = e.pageY;
+ },
+
+ /**
+ element
+ type
+ func
+ */
+ attach: function(element, type, func){
+ //
+ if(element.addEventListener){
+ element.addEventListener(type, func, false);
+ }
+ },
+
+ /*
+ returns -1 or 1
+ scrolling towards user is 1
+ scrolling towards screen is -1
+ should this return an object or a single value?
+ */
+ _mouseScroll: function(evt){
+ var delta = 0;
+
+ // which check to use?
+ //if(browser === MINEFIELD){
+ if(evt.detail){
+ delta = evt.detail / 3;
+ }
+ else if(evt.wheelDelta){
+ delta = -evt.wheelDelta / 360;
+ }
+
+ if(xb.onMouseScroll){
+ xb.onMouseScroll(delta);
+ }
+ },
+
+ _mousePressed: function(evt){
+ if(xb.onMousePressed){
+ xb.onMousePressed();
+ }
+ },
+
+ _mouseReleased: function(){
+ if(xb.onMouseReleased){
+ xb.onMouseReleased();
+ }
+ },
+
+ /**
+ cvs
+ renderCB
+ */
+ setup: function(cvs, renderCB){
+ canvas = cvs;
+ browser = getUserAgent(navigator.userAgent);
+
+ lastTime = new Date();
+ frames = 0;
+
+ xb.resize(canvas.getAttribute("width"), canvas.getAttribute("height"));
+
+ xb.renderCallback = renderCB;
+ setInterval(xb.renderCallback, 10);
+
+ xb.attach(cvs, "mouseup", xb._mouseReleased);
+ xb.attach(cvs, "mousedown", xb._mousePressed);
+ xb.attach(cvs, "mousemove", xb.mouseMove);
+ xb.attach(cvs, "DOMMouseScroll", xb._mouseScroll);
+ xb.attach(cvs, "mousewheel", xb._mouseScroll);
+ },
+
+ /**
+ 1 arg = uniform scaling
+ 3 args = independant scaling
+ */
+ scale: function(sx, sy, sz){
+
+ // uniform scaling
+ if( !sy && !sz){
+ model = M4x4.scale1(sx, model);
+ }
+ else{
+ model = M4x4.scale3(sx, sy, sz, model);
+ }
+ },
+
+ /**
+ tx
+ ty
+ tz
+ */
+ translate: function(tx, ty, tz){
+ model = M4x4.translate3(tx, ty, tz, model, model);
+ },
+
+ /**
+ radians
+ */
+ rotateY: function(radians){
+ model = M4x4.rotate(radians,V3.$(0,1,0),model);
+ },
+
+ /**
+ constant
+ linear
+ quadratic
+ */
+ attenuation: function(constant, linear, quadratic){
+ uniformf(progObj, "attenuation", [constant, linear, quadratic]);
+ },
+
+ /**
+ size - in pixels
+ */
+ pointSize: function(size){
+ uniformf(progObj, "pointSize", size);
+ },
+
+ /**
+ radians
+ */
+ rotateX: function(radians){
+ model = M4x4.rotate(radians,V3.$(1,0,0),model);
+ },
+
+ /**
+ radians
+ */
+ rotateZ: function(radians){
+ model = M4x4.rotate(radians,V3.$(0,0,1),model);
+ },
+
+ /**
+ o - object such as {path:"acorn.asc", autoCenter: true}
+ */
+ loadFile: function(o){
+ var path = o.path;
+
+ // need ||?
+ var autoCenter = o.autoCenter || false;
+
+ var AJAX = new XMLHttpRequest();
+
+ // this doesn't work
+ // AJAX.addEventListener("progress", f,false);
+
+ AJAX.open("GET", path, true);
+ AJAX.send(null);
+
+ var file = {
+ status: 0,
+ progress: 0,
+ numPoints: 0,
+ };
+
+ AJAX.onreadystatechange =
+ function(){
+ //??
+ if(AJAX.status === 200){
+ file.status = 1;
+ }
+
+ if(AJAX.readyState === XHR_DONE){
+
+ var code = getDataLayout(AJAX.responseText);
+
+ var normalsPresent = false;
+ var colorsPresent = false;
+
+ if(code == 1 ){
+ code = 6;
+ normalsPresent = true;
+ }
+ else if(code ==2 ){
+ code = 6;
+ colorsPresent = true;
+ }
+ if(code ==9){
+ normalsPresent = true;
+ colorsPresent = true;
+
+ }
+
+ var values = AJAX.responseText.split(/\s+/);
+
+ const numVerts = values.length/code;
+
+ var objCenter = [0,0,0];
+
+ // xyz rgb normals
+ for(var i = 0, len = values.length; i < len; i += code){
+ var currX = parseFloat(values[i]);
+ var currY = parseFloat(values[i+1]);
+ var currZ = parseFloat(values[i+2]);
+
+ verts.push(currX);
+ verts.push(currY);
+ verts.push(currZ);
+
+ // don't waste cycles if the user didn't want it centered.
+ if(autoCenter){
+ objCenter[0] += currX;
+ objCenter[1] += currY;
+ objCenter[2] += currZ;
+ }
+
+ if(colorsPresent){
+ cols.push(parseInt(values[i+3])/255);
+ cols.push(parseInt(values[i+4])/255);
+ cols.push(parseInt(values[i+5])/255);
+ }
+
+ if(normalsPresent){
+ norms.push(parseFloat(values[i+6]));
+ norms.push(parseFloat(values[i+7]));
+ norms.push(parseFloat(values[i+8]));
+ }
+ }
+
+ // if the user wants to center the point cloud
+ if(autoCenter){
+ objCenter[0] /= numVerts;
+ objCenter[1] /= numVerts;
+ objCenter[2] /= numVerts;
+ }
+
+ // if the user wanted to autocenter the point cloud,
+ // iterate over all the verts and subtract by the
+ // point cloud's current center.
+ if(autoCenter){
+ for(var i = 0; i < numVerts; i++){
+ verts[i*3] -= objCenter[0];
+ verts[i*3+1] -= objCenter[1];
+ verts[i*3+2] -= objCenter[2];
+ }
+ }
+
+ VBOs = createVBOs(verts, cols, norms);
+
+ file.status = 4;
+ }
+ }
+ return file;
+ }
+
+ }
+ return xb;
+};