diff --git a/demos/many_clouds/index.html b/demos/many_clouds/index.html
index 8d577ba..5a65580 100644
--- a/demos/many_clouds/index.html
+++ b/demos/many_clouds/index.html
@@ -10,7 +10,7 @@
-
+
diff --git a/demos/many_clouds/many_clouds.js b/demos/many_clouds/js/many_clouds.js
similarity index 97%
rename from demos/many_clouds/many_clouds.js
rename to demos/many_clouds/js/many_clouds.js
index 8a06d6c..89dcf0c 100644
--- a/demos/many_clouds/many_clouds.js
+++ b/demos/many_clouds/js/many_clouds.js
@@ -128,9 +128,7 @@ function render() {
function start(){
ps = new PointStream();
ps.setup(document.getElementById('canvas'));
- ps.background([.3,.6, .9,1]);
- ps.background([1,1,1,1]);
- //ps.background([1,1,1,0.1]);
+ ps.background([1,1,1,1]);
ps.onRender = render
ps.onMouseScroll = zoom;
diff --git a/demos/many_clouds/shaders/acorn_shader.js b/demos/many_clouds/shaders/acorn_shader.js
index 8e98041..512c9bb 100644
--- a/demos/many_clouds/shaders/acorn_shader.js
+++ b/demos/many_clouds/shaders/acorn_shader.js
@@ -16,27 +16,17 @@ var acornVertShader =
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
-"uniform vec3 XBPS_attenuation;" +
+"uniform vec3 ps_Attenuation;" +
"uniform mat4 ps_ModelViewMatrix;" +
"uniform mat4 ps_ProjectionMatrix;" +
"uniform mat4 ps_NormalMatrix;" +
-"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" +
- // Get the vector from the light to the vertex
-" vec3 VP = vec3(0.0, 150.0, 150.0) - 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 ));" +
-" col += vec3(0.7, 0.7, 1.0) * nDotVP;" +
+"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal) {" +
+" vec3 VP = -ecPos;" +
+" VP = normalize(VP);" +
+" float nDotVP = max(0.0, dot(vertNormal, VP));" +
+" col = vec3(1.0, 1.0, 1.0) * nDotVP;" +
"}" +
"void main(void) {" +
@@ -44,24 +34,17 @@ var acornVertShader =
" vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" +
" vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
-" vec3 eye = vec3( 0.0, 0.0, 1.0 );" +
-" vec3 col = vec3(0.0, 0.0, 0.0);" +
-" PointLight(col, ecPos, transNorm, eye);" +
+" vec3 col;" +
+" PointLight(col, ecPos, transNorm);" +
" frontColor = ps_Color * vec4(col, 1.0);" +
-" float dist = length( ecPos4 );" +
-" float attn = XBPS_attenuation[0] + " +
-" (XBPS_attenuation[1] * dist) + " +
-" (XBPS_attenuation[2] * dist * dist);" +
-
-" if(attn > 0.0){" +
-" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
-" }" +
-" else{" +
-" gl_PointSize = 1.0;" +
-" }"+
+" float dist = length(ecPos4);" +
+" float attn = ps_Attenuation[0] + " +
+" (ps_Attenuation[1] * dist) + " +
+" (ps_Attenuation[2] * dist * dist);" +
+" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
" gl_Position = ps_ProjectionMatrix * ecPos4;" +
"}";
diff --git a/demos/many_clouds/shaders/mickey_shader.js b/demos/many_clouds/shaders/mickey_shader.js
index 2432586..e009a41 100644
--- a/demos/many_clouds/shaders/mickey_shader.js
+++ b/demos/many_clouds/shaders/mickey_shader.js
@@ -17,7 +17,7 @@ var mickeyVertShader =
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
-"uniform vec3 XBPS_attenuation;" +
+"uniform vec3 ps_Attenuation;" +
"uniform mat4 ps_ModelViewMatrix;" +
"uniform mat4 ps_ProjectionMatrix;" +
@@ -36,9 +36,9 @@ var mickeyVertShader =
" vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
" float dist = length( ecPos4 );" +
-" float attn = XBPS_attenuation[0] + " +
-" (XBPS_attenuation[1] * dist) + " +
-" (XBPS_attenuation[2] * dist * dist);" +
+" float attn = ps_Attenuation[0] + " +
+" (ps_Attenuation[1] * dist) + " +
+" (ps_Attenuation[2] * dist * dist);" +
" gl_PointSize = attn > 0.0 ? ps_PointSize * sqrt(1.0/attn) : 1.0;" +
diff --git a/notes.txt b/notes.txt
deleted file mode 100644
index f8acf10..0000000
--- a/notes.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-If writing a parser and using the XB PointStream built-in shader,
-you must ensure the parser set the correct attribute names
-
-XBPS_aVertex
-XBPS_aColor
-
-
-XBPS_model
-XBPS_view
-XBPS_modelView
-XBPS_perspective
-
-XBPS_pointSize
-
-
-use XBPS shaders and parser
-- Only position and colors will be available
-
-use XBPS parser
-- You must read XBPS attribute names in your shader
-
-use XBPS shader
-- You must write to XBPS attribute names in your parser
-
-use custom shader and parser
-- any attribute names can be read and written to, except you must use
-
-XBPS_model
-XBPS_view
-XBPS_modelView
-XBPS_normalMatrix
-XBPS_perspective
-XBPS_pointSize
-
diff --git a/psapi.js b/psapi.js
index 5a8463d..8adf2a1 100644
--- a/psapi.js
+++ b/psapi.js
@@ -122,7 +122,7 @@ var PointStream = (function() {
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
- "uniform vec3 XBPS_attenuation;" +
+ "uniform vec3 ps_Attenuation;" +
"uniform mat4 ps_ModelViewMatrix;" +
"uniform mat4 ps_ProjectionMatrix;" +
@@ -131,9 +131,9 @@ var PointStream = (function() {
" frontColor = ps_Color;" +
" vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" +
" float dist = length(ecPos4);" +
- " float attn = XBPS_attenuation[0] + " +
- " (XBPS_attenuation[1] * dist) + " +
- " (XBPS_attenuation[2] * dist * dist);" +
+ " float attn = ps_Attenuation[0] + " +
+ " (ps_Attenuation[1] * dist) + " +
+ " (ps_Attenuation[2] * dist * dist);" +
" if(attn > 0.0){" +
" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
@@ -146,14 +146,14 @@ var PointStream = (function() {
"}";
var fragmentShaderSource =
- "#ifdef GL_ES\n" +
- "precision highp float;\n" +
- "#endif\n" +
-
- "varying vec4 frontColor;" +
- "void main(void){" +
- " gl_FragColor = frontColor;" +
- "}";
+ '#ifdef GL_ES \n\
+ precision highp float; \n\
+ #endif \n\
+ \n\
+ varying vec4 frontColor; \n\
+ void main(void){ \n\
+ gl_FragColor = frontColor; \n\
+ }';
/**
set a uniform integer
@@ -788,6 +788,23 @@ var PointStream = (function() {
}
}
+ // !! fix (remove from global ns)
+ function getAverage(arr){
+ var objCenter = [0, 0, 0];
+
+ for(var i = 0; i < arr.length; i += 3){
+ objCenter[0] += arr[i];
+ objCenter[1] += arr[i+1];
+ objCenter[2] += arr[i+2];
+ }
+
+ objCenter[0] /= arr.length/3;
+ objCenter[1] /= arr.length/3;
+ objCenter[2] /= arr.length/3;
+
+ return objCenter;
+ }
+
/**
Sets variables to default values.
*/
@@ -1171,7 +1188,7 @@ var PointStream = (function() {
*/
this.setDefaultUniforms = function(){
uniformf(currProgram, "ps_PointSize", 1);
- uniformf(currProgram, "XBPS_attenuation", [attn[0], attn[1], attn[2]]);
+ uniformf(currProgram, "ps_Attenuation", [attn[0], attn[1], attn[2]]);
uniformMatrix(currProgram, "ps_ProjectionMatrix", false, projectionMatrix);
};
@@ -1262,7 +1279,7 @@ var PointStream = (function() {
@param {Number} quadratic -
*/
this.attenuation = function(constant, linear, quadratic){
- uniformf(currProgram, "attenuation", [constant, linear, quadratic]);
+ uniformf(currProgram, "ps_Attenuation", [constant, linear, quadratic]);
};
/**
@@ -1338,20 +1355,3 @@ var PointStream = (function() {
return PointStream;
}());
-
-// !! fix (remove from global ns)
-var getAverage = function(arr){
- var objCenter = [0, 0, 0];
-
- for(var i = 0; i < arr.length; i += 3){
- objCenter[0] += arr[i];
- objCenter[1] += arr[i+1];
- objCenter[2] += arr[i+2];
- }
-
- objCenter[0] /= arr.length/3;
- objCenter[1] /= arr.length/3;
- objCenter[2] /= arr.length/3;
-
- return objCenter;
-}
diff --git a/tests/user_parser/user_asc_parser.js b/tests/user_parser/user_asc_parser.js
index c1578cf..affd649 100644
--- a/tests/user_parser/user_asc_parser.js
+++ b/tests/user_parser/user_asc_parser.js
@@ -10,7 +10,12 @@
Notes:
This parser parses .ASC filetypes. These files are ASCII
files which have their data stored in one of the following ways:
-
+
+ This particular parser is meant to be used with the built-in XB
+ PointStream shader, therefore it only reads in vertex positions
+ and colors.
+
+ .ASC structure can be one of:
X, Y, Z
X, Y, Z, R, G, B
X, Y, Z, I, J, K
@@ -53,12 +58,7 @@ var User_ASC_Parser = (function() {
var normalsPresent = false;
var colorsPresent = false;
var layoutCode = UNKNOWN;
-
- //
- var parsedVerts = [];
- var parsedCols = [];
- var parsedNorms = [];
-
+
// keep track if onprogress event handler was called to
// handle Chrome/WebKit vs. Minefield differences.
//
@@ -79,9 +79,9 @@ var User_ASC_Parser = (function() {
ASC files can either contain
X, Y, Z
- X, Y, Z, R, G, B
- X, Y, Z, NX, NY, NZ
- X, Y, Z, R, G, B, NX, NY, NZ
+ X, Y, Z, R, G, B
+ X, Y, Z, I, J, K
+ X, Y, Z, R, G, B, I, J, K
@returns {Number}
0 first case
@@ -299,16 +299,15 @@ var User_ASC_Parser = (function() {
var verts = new Float32Array(numVerts * 3);
var cols = colorsPresent ? new Float32Array(numVerts * 3) : null;
- var norms = normalsPresent ? new Float32Array(numVerts * 3) : null;
- // depending if there are colors,
+ // depending if there are colors,
// we'll need to read different indices.
// if there aren't:
- // x y z r g b nx ny nz
+ // x y z r g b i j k
// 0 1 2 3 4 5 6 7 8 <- normals start at index 6
//
// if there are:
- // x y z nx ny nz
+ // x y z i j k
// 0 1 2 3 4 5 <- normals start at index 3
var valueOffset = 0;
if(colorsPresent){
@@ -327,31 +326,15 @@ var User_ASC_Parser = (function() {
cols[j+1] = parseInt(chunk[i+4])/255;
cols[j+2] = parseInt(chunk[i+5])/255;
}
-
- if(norms){
- norms[j] = parseFloat(chunk[i + 3 + valueOffset]);
- norms[j+1] = parseFloat(chunk[i + 4 + valueOffset]);
- norms[j+2] = parseFloat(chunk[i + 5 + valueOffset]);
- }
}
-
- // !! pushing on null?
- parsedVerts.push(verts);
- parsedCols.push(cols);
- parsedNorms.push(norms);
-
+
// XB PointStream expects an object with named/value pairs
// which contain the attribute arrays. These must match attribute
// names found in the shader
- // attributes {
- // "VERTEX" : [...],
- // "COLOR" : [...]
- // }
var attributes = {};
if(verts){attributes["ps_Vertex"] = verts;}
if(cols){attributes["ps_Color"] = cols;}
- if(norms){attributes["ps_Normal"] = norms;}
parse(AJAX.parser, attributes);
}
diff --git a/tests/user_parser/user_parser.js b/tests/user_parser/user_parser.js
index aeb6dea..014f276 100644
--- a/tests/user_parser/user_parser.js
+++ b/tests/user_parser/user_parser.js
@@ -18,12 +18,11 @@ function render() {
function start(){
ps = new PointStream();
ps.setup(document.getElementById('canvas'));
+ ps.registerParser("asc", User_ASC_Parser);
ps.onRender = render;
ps.background([1, 1, 1, 1]);
ps.pointSize(5);
-
- ps.registerParser("asc", User_ASC_Parser);
acorn = ps.load("../../clouds/acorn.asc");
}
diff --git a/tests/user_parser_and_shader/index.html b/tests/user_parser_and_shader/index.html
new file mode 100644
index 0000000..9e0822c
--- /dev/null
+++ b/tests/user_parser_and_shader/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This test makes sure the user can specify their own parser and hook it into
+ the library.
+
+
+
+
+
+
+
diff --git a/tests/user_parser_and_shader/user_asc_parser.js b/tests/user_parser_and_shader/user_asc_parser.js
new file mode 100644
index 0000000..affd649
--- /dev/null
+++ b/tests/user_parser_and_shader/user_asc_parser.js
@@ -0,0 +1,402 @@
+/*
+ Copyright (c) 2010 Seneca College
+ MIT LICENSE
+
+ Version: 0.1
+ Author: Andor Salga
+ asalga.wordpress.com
+ Date: November 16, 2010
+
+ Notes:
+ This parser parses .ASC filetypes. These files are ASCII
+ files which have their data stored in one of the following ways:
+
+ This particular parser is meant to be used with the built-in XB
+ PointStream shader, therefore it only reads in vertex positions
+ and colors.
+
+ .ASC structure can be one of:
+ X, Y, Z
+ X, Y, Z, R, G, B
+ X, Y, Z, I, J, K
+ X, Y, Z, R, G, B, I, J, K
+*/
+
+var User_ASC_Parser = (function() {
+
+ /**
+ Constructor
+ */
+ function User_ASC_Parser(config) {
+
+ var undef;
+
+ // defined once to reduce number of empty functions
+ var __empty_func = function(){};
+
+ var start = config.start || __empty_func;
+ var parse = config.parse || __empty_func;
+ var end = config.end || __empty_func;
+
+ var version = "0.1";
+
+ const UNKNOWN = -1;
+
+ const XHR_DONE = 4;
+ const STARTED = 1;
+
+ var pathToFile = null;
+ var fileSizeInBytes = 0;
+
+ //
+ var numParsedPoints = 0;
+ var numTotalPoints = 0;
+ var progress = 0;
+
+ //
+ var numValuesPerLine = -1;
+ var normalsPresent = false;
+ var colorsPresent = false;
+ var layoutCode = UNKNOWN;
+
+ // keep track if onprogress event handler was called to
+ // handle Chrome/WebKit vs. Minefield differences.
+ //
+ // Minefield will call onprogress zero or many times
+ // Chrome/WebKit will call onprogress one or many times
+ var onProgressCalled = false;
+ var AJAX = null;
+
+ // WebGL compatibility wrapper
+ try{
+ Float32Array;
+ }catch(ex){
+ Float32Array = WebGLFloatArray;
+ }
+
+ /**
+ @private
+
+ ASC files can either contain
+ X, Y, Z
+ X, Y, Z, R, G, B
+ X, Y, Z, I, J, K
+ X, Y, Z, R, G, B, I, J, K
+
+ @returns {Number}
+ 0 first case
+ 1 second case
+ 2 third case
+ 3 fourth case
+ */
+ var getDataLayout = function(values){
+ var normalsPresent = false;
+ var colorsPresent = false;
+
+ var VERTS = 0;
+ var VERTS_COLS = 1;
+ var VERTS_NORMS = 2;
+ var VERTS_COLS_NORMS = 3;
+
+ // 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');
+
+ // Vertices, Colors, Normals:
+ // 1.916 -2.421 -4.0 64 32 16 -0.3727 -0.2476 -0.8942
+ if(numSpaces === 8){
+ return VERTS_COLS_NORMS;
+ }
+
+ // Just vertices:
+ // 1.916 -2.421 -4.0339
+ if(numSpaces == 2){
+ return VERTS;
+ }
+
+ var str = "";
+
+ //
+ // !! fix me
+ 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 VERTS_NORMS;
+ }
+ }
+
+ // Vertices and Normals:
+ // 1.916 -2.421 -4.0 -0.3727 -0.2476 -0.8942
+ return VERTS_COLS;
+ };
+
+ /*
+ Returns the version of this parser.
+
+ @returns {String} parser version.
+ */
+ this.__defineGetter__("version", function(){
+ return version;
+ });
+
+ /*
+ Get the number of parsed points so far.
+
+ @returns {Number} number of points parsed.
+ */
+ this.__defineGetter__("numParsedPoints", function(){
+ return numParsedPoints;
+ });
+
+ /*
+ Get the total number of points in the point cloud.
+
+ @returns {Number}
+ */
+ this.__defineGetter__("numTotalPoints", function(){
+ return numTotalPoints;
+ });
+
+ /**
+ Returns the progress of downloading the point cloud between zero and one.
+
+ @returns {Number} value from zero to one or -1 if unknown.
+ */
+ this.__defineGetter__("progress", function(){
+ return progress;
+ });
+
+ /**
+ Returns the file size of the resource in bytes.
+
+ @returns {Number} size of resource in bytes.
+ */
+ this.__defineGetter__("fileSize", function(){
+ return fileSizeInBytes;
+ });
+
+ /**
+ @param path Path to the resource
+ */
+ this.load = function(path){
+ pathToFile = path;
+
+ AJAX = new XMLHttpRequest();
+
+ // put a reference to the parser in the AJAX object
+ // so we can give the library a reference to the
+ // parser within the AJAX event handler scope.
+ // !! eventually need to fix this
+ AJAX.parser = this;
+
+ /**
+ occurs exactly once when the resource begins
+ to be downloaded
+ */
+ AJAX.onloadstart = function(evt){
+ start(AJAX.parser);
+ };
+
+ /*
+ occurs exactly once, when the file is done
+ being downloaded
+ */
+ AJAX.onload = function(evt){
+
+ var ascData = AJAX.responseText;
+ var chunk = null;
+
+ // if the onprogress event didn't get called--we simply got
+ // the file in one go, we can parse from start to finish.
+ if(onProgressCalled === false){
+ chunk = ascData;
+ }
+ // otherwise the onprogress event was called at least once,
+ // that means we need to get the data from a specific point to the end.
+ else if(ascData.length - AJAX.lastNewLineIndex > 1){
+ chunk = ascData.substring(AJAX.lastNewLineIndex, ascData.length);
+ }
+
+ // if the last chunk doesn't have any digits (just spaces)
+ // don't parse it.
+ if(chunk && chunk.match(/[0-9]/)){
+ AJAX.parseChunk(chunk);
+ }
+
+ numTotalPoints = numParsedPoints;
+
+ progress = 1;
+
+ end(AJAX.parser);
+ }
+
+ /**
+ !! fix me
+ */
+ AJAX.parseChunk = function(chunkData){
+ var chunk = chunkData;
+
+ // !! fix this
+ // this occurs over network connections, but not locally.
+ if(chunk !== ""){
+
+ // !! fix this
+ if(layoutCode === UNKNOWN){
+ layoutCode = getDataLayout(chunk);
+ numValuesPerLine = -1;
+
+ switch(layoutCode){
+ case 0: numValuesPerLine = 3;
+ break;
+ case 1: numValuesPerLine = 6;
+ colorsPresent = true;
+ break;
+ case 2: numValuesPerLine = 6;
+ normalsPresent = true;
+ break;
+ case 3: numValuesPerLine = 9;
+ normalsPresent = true;
+ colorsPresent = true;
+ break;
+ }
+ gotLayout = true;
+ }
+
+ // trim trailing spaces
+ chunk = chunk.replace(/\s+$/,"");
+
+ // trim leading spaces
+ chunk = chunk.replace(/^\s+/,"");
+
+ // split on white space
+ chunk = chunk.split(/\s+/);
+
+ var numVerts = chunk.length/numValuesPerLine;
+ numParsedPoints += numVerts;
+
+ var verts = new Float32Array(numVerts * 3);
+ var cols = colorsPresent ? new Float32Array(numVerts * 3) : null;
+
+ // depending if there are colors,
+ // we'll need to read different indices.
+ // if there aren't:
+ // x y z r g b i j k
+ // 0 1 2 3 4 5 6 7 8 <- normals start at index 6
+ //
+ // if there are:
+ // x y z i j k
+ // 0 1 2 3 4 5 <- normals start at index 3
+ var valueOffset = 0;
+ if(colorsPresent){
+ valueOffset = 3;
+ }
+
+ // xyz rgb normals
+ for(var i = 0, j = 0, len = chunk.length; i < len; i += numValuesPerLine, j += 3){
+ verts[j] = parseFloat(chunk[i]);
+ verts[j+1] = parseFloat(chunk[i+1]);
+ verts[j+2] = parseFloat(chunk[i+2]);
+
+ // XBPS spec for parsers requires colors to be normalized
+ if(cols){
+ cols[j] = parseInt(chunk[i+3])/255;
+ cols[j+1] = parseInt(chunk[i+4])/255;
+ cols[j+2] = parseInt(chunk[i+5])/255;
+ }
+ }
+
+ // XB PointStream expects an object with named/value pairs
+ // which contain the attribute arrays. These must match attribute
+ // names found in the shader
+
+ var attributes = {};
+ if(verts){attributes["ps_Vertex"] = verts;}
+ if(cols){attributes["ps_Color"] = cols;}
+
+ parse(AJAX.parser, attributes);
+ }
+ };
+
+ /**
+ On Minefield, this will occur zero or many times
+ On Chrome/WebKit this will occur one or many times
+ */
+ AJAX.onprogress = function(evt){
+
+ if(evt.lengthComputable){
+ fileSizeInBytes = evt.total;
+ progress = evt.loaded/evt.total;
+ }
+
+ onProgressCalled = true;
+
+ // if we have something to actually parse
+ if(AJAX.responseText){
+ var ascData = AJAX.responseText;
+
+ // we likely stopped getting data somewhere in the middle of
+ // a line in the ASC file
+
+ // 5.813 2.352 6.500 0 0 0 2.646 3.577 2.516\n
+ // 1.079 1.296 9.360 0 0 0 4.307 1.181 5.208\n
+ // 3.163 2.225 6.139 0 0 0 0.6<-- stopped here
+
+ // So find the last known newline. Everything from the last
+ // request to this last newline can be placed in a buffer.
+ var lastNewLineIndex = ascData.lastIndexOf("\n");
+ AJAX.lastNewLineIndex = lastNewLineIndex;
+
+ // if the status just changed and we finished downloading the
+ // file, grab everyting until the end. If there is only a bunch
+ // of whitespace, make a note of that and don't bother parsing.
+ if(AJAX.readyState === XHR_DONE){
+ var chunk = ascData.substring(AJAX.startOfNextChunk, ascData.length);
+ // If the last chunk doesn't have any digits (just spaces)
+ // don't parse it.
+ if(chunk.match(/[0-9]/)){
+ AJAX.parseChunk(chunk);
+ }
+ }
+ // if we still have more data to go
+ else{
+ // Start of the next chunk starts after the newline.
+ var chunk = ascData.substring(AJAX.startOfNextChunk, lastNewLineIndex + 1);
+ AJAX.startOfNextChunk = lastNewLineIndex + 1;
+ AJAX.parseChunk(chunk);
+ }
+ }
+ };//onprogress
+
+ // open an asynchronous request to the path
+ if(AJAX.overrideMimeType){
+ AJAX.overrideMimeType("application/json");
+ }
+ AJAX.open("GET", path, true);
+ AJAX.send(null);
+ };// load
+ }//ctor
+ return User_ASC_Parser;
+}());
diff --git a/tests/user_parser_and_shader/user_parser.js b/tests/user_parser_and_shader/user_parser.js
new file mode 100644
index 0000000..014f276
--- /dev/null
+++ b/tests/user_parser_and_shader/user_parser.js
@@ -0,0 +1,28 @@
+var ps, acorn;
+var i = 0.0;
+var j = 5.0;
+
+function render() {
+
+ ps.translate(0, 0, -20);
+ ps.rotateY(i += 0.0011);
+ ps.rotateZ(j += 0.0015);
+
+ var c = acorn.getCenter();
+ ps.translate(-c[0], -c[1], -c[2]);
+
+ ps.clear();
+ ps.render(acorn);
+}
+
+function start(){
+ ps = new PointStream();
+ ps.setup(document.getElementById('canvas'));
+ ps.registerParser("asc", User_ASC_Parser);
+ ps.onRender = render;
+
+ ps.background([1, 1, 1, 1]);
+ ps.pointSize(5);
+
+ acorn = ps.load("../../clouds/acorn.asc");
+}
diff --git a/tests/user_shader/shaders.js b/tests/user_shader/shaders.js
index cd04016..4203bdc 100644
--- a/tests/user_shader/shaders.js
+++ b/tests/user_shader/shaders.js
@@ -6,7 +6,7 @@ var vertShader =
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
-"uniform vec3 XBPS_attenuation;" +
+"uniform vec3 ps_Attenuation;" +
"uniform vec3 lightPos;" +
"uniform bool reflection;"+
@@ -15,25 +15,10 @@ var vertShader =
"uniform mat4 ps_ProjectionMatrix;" +
"uniform mat4 ps_NormalMatrix;" +
-"float dirLight(in vec3 norm){" +
-" vec3 light = vec3(0.0, 1.0, 0.0);" +
-" return max(dot(light, norm), 0.0);" +
-"}" +
-
-"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal, in vec3 eye ) {" +
- // Get the vector from the light to the vertex
+"void PointLight(inout vec3 col, in vec3 ecPos, in vec3 vertNormal) {" +
" vec3 VP = lightPos - 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 ));" +
" col += vec3(1.0, 1.0, 1.0) * nDotVP;" +
"}" +
@@ -42,10 +27,9 @@ var vertShader =
" vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" +
" vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" +
-" vec3 eye = vec3( 0.0, 0.0, 1.0 );" +
" vec3 col = vec3(0.0, 0.0, 0.0);" +
-" PointLight(col, ecPos, transNorm, eye);" +
+" PointLight(col, ecPos, transNorm);" +
" frontColor = ps_Color * vec4(col, 1.0);" +
@@ -57,17 +41,11 @@ var vertShader =
" }" +
" float dist = length( ecPos4 );" +
-" float attn = XBPS_attenuation[0] + " +
-" (XBPS_attenuation[1] * dist) + " +
-" (XBPS_attenuation[2] * dist * dist);" +
-
-" if(attn > 0.0){" +
-" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
-" }" +
-" else{" +
-" gl_PointSize = 1.0;" +
-" }"+
+" float attn = ps_Attenuation[0] + " +
+" (ps_Attenuation[1] * dist) + " +
+" (ps_Attenuation[2] * dist * dist);" +
+" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
" gl_Position = ps_ProjectionMatrix * ecPos4;" +
"}";
diff --git a/tests/user_shader/user_shader.js b/tests/user_shader/user_shader.js
index b18b928..5f7433f 100644
--- a/tests/user_shader/user_shader.js
+++ b/tests/user_shader/user_shader.js
@@ -1,63 +1,54 @@
-var mickey = null;
-var ps = null;
-var i = 0.0;
+var ps, mickey;
+var rotY = 0.0;
+var rotX = 0.3;
-var reflectionShader;
-var objectShader;
-var toggle = false;
-
-function keyDown(){
-}
+var progObj;
+var fps_label;
function render() {
ps.clear();
- var center = [-1.1931838002830566,0.2915859633078008,-0.6363419673371361];
-
- i += 0.05;
+ // spin object
+ rotY += 0.01;
// Draw reflection
ps.uniformi("reflection", true);
ps.uniformf("lightPos", [0, -50, 10]);
ps.uniformf("uReflection", [.15, .15, .3, .8]);
ps.pushMatrix();
- ps.translate(0, 20, -80);
- ps.rotateX(1.0);
+ ps.translate(0, 10, -80);
+ ps.rotateX(rotX);
ps.translate(0, -55, 0);
ps.scale(1, -1, 1);
- ps.rotateY(i);
+ ps.rotateY(rotY);
ps.render(mickey);
ps.popMatrix();
// Draw object
ps.uniformi("reflection", false);
ps.uniformf("lightPos", [0, 50, 10]);
- ps.uniformf("uReflection", [1,1,1,1]);
+ ps.uniformf("uReflection", [1, 1, 1, 1]);
ps.pushMatrix();
- ps.translate(0, 20, -80);
- ps.rotateX(1.0);
- ps.rotateY(i);
+ ps.translate(0, 10, -80);
+ ps.rotateX(rotX);
+ ps.rotateY(rotY);
ps.render(mickey);
ps.popMatrix();
- var fps = Math.floor(ps.frameRate);
- var fps_label = document.getElementById("fps");
- fps_label.innerHTML = fps + " FPS";
+ fps_label.innerHTML = Math.floor(ps.frameRate) + " FPS";
}
function start(){
+ fps_label = document.getElementById("fps");
+
ps = new PointStream();
ps.setup(document.getElementById('canvas'));
- objectShader = ps.createProgram(vertShader, fragShader);
- ps.useProgram(objectShader);
- ps.pointSize(10);
-
ps.onRender = render;
- ps.onKeyDown = keyDown;
-
- //ps.background([0, 0, 0, 0.7]);
- //ps.background([0.5, 0.5, 0.5, 1.0]);
- ps.background([1.0, 1.0, 1.0, 1.0]);
+ ps.background([1, 1, 1, 1]);
+ progObj = ps.createProgram(vertShader, fragShader);
+ ps.useProgram(progObj);
+ ps.pointSize(10);
+
mickey = ps.load("../../clouds/mickey.asc");
}
diff --git a/tests/user_shader_2/shaders.js b/tests/user_shader_2/shaders.js
index 41fb99c..61d5f07 100644
--- a/tests/user_shader_2/shaders.js
+++ b/tests/user_shader_2/shaders.js
@@ -16,7 +16,7 @@ var cel_vertShader =
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
-"uniform vec3 XBPS_attenuation;" +
+"uniform vec3 ps_Attenuation;" +
"uniform mat4 ps_ModelViewMatrix;" +
"uniform mat4 ps_ProjectionMatrix;" +
@@ -35,24 +35,18 @@ var cel_vertShader =
" float intensity;" +
" PointLight(intensity, vec3(ecPos4), transNorm);" +
-" if(intensity <= 0.6){ intensity = 0.5;}" +
+" if (intensity <= 0.6){ intensity = 0.6;}" +
" else if(intensity <= 0.8){ intensity = 0.8;}" +
" else if(intensity <= 1.0){ intensity = 1.0;}" +
" frontColor = ps_Color * vec4(intensity, intensity, intensity, 1.0);" +
" float dist = length( ecPos4 );" +
-" float attn = XBPS_attenuation[0] + " +
-" (XBPS_attenuation[1] * dist) + " +
-" (XBPS_attenuation[2] * dist * dist);" +
-
-" if(attn > 0.0){" +
-" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
-" }" +
-" else{" +
-" gl_PointSize = 1.0;" +
-" }"+
+" float attn = ps_Attenuation[0] + " +
+" (ps_Attenuation[1] * dist) + " +
+" (ps_Attenuation[2] * dist * dist);" +
+" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
" gl_Position = ps_ProjectionMatrix * ecPos4;" +
"}";
@@ -74,7 +68,7 @@ var scan_vertShader =
"attribute vec4 ps_Color;" +
"uniform float ps_PointSize;" +
-"uniform vec3 XBPS_attenuation;" +
+"uniform vec3 ps_Attenuation;" +
"uniform mat4 ps_ModelViewMatrix;" +
"uniform mat4 ps_ProjectionMatrix;" +
@@ -85,16 +79,10 @@ var scan_vertShader =
" vec4 ecPos4 = ps_ModelViewMatrix * vec4(ps_Vertex, 1.0);" +
" float dist = length( ecPos4 );" +
-" float attn = XBPS_attenuation[0] + " +
-" (XBPS_attenuation[1] * dist) + " +
-" (XBPS_attenuation[2] * dist * dist);" +
-
-" if(attn > 0.0){" +
-" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
-" }" +
-" else{" +
-" gl_PointSize = 1.0;" +
-" }"+
+" float attn = ps_Attenuation[0] + " +
+" (ps_Attenuation[1] * dist) + " +
+" (ps_Attenuation[2] * dist * dist);" +
+" gl_PointSize = ps_PointSize * sqrt(1.0/attn);" +
" gl_Position = ps_ProjectionMatrix * ecPos4;" +
"}";
diff --git a/tests/verts_cols/verts_colors.js b/tests/verts_cols/verts_colors.js
index 172a92c..c92e195 100644
--- a/tests/verts_cols/verts_colors.js
+++ b/tests/verts_cols/verts_colors.js
@@ -1,13 +1,12 @@
var ps, pointCloud;
function render() {
- ps.translate(0, 0, -30);
-
var c = pointCloud.getCenter();
- ps.translate(-c[0], -c[1], -c[2]);
+ ps.translate(-c[0], -c[1], -30-c[2]);
ps.clear();
ps.render(pointCloud);
+
if(pointCloud.getStatus() === 3){
ps.onRender = function(){};
}
@@ -16,8 +15,10 @@ function render() {
function start(){
ps = new PointStream();
ps.setup(document.getElementById('canvas'));
+ ps.onRender = render;
+
ps.background([0, 0, 0, 0.5]);
ps.pointSize(5);
- ps.onRender = render;
+
pointCloud = ps.load("../../clouds/mickey_verts_cols.asc");
}
diff --git a/tests/verts_norms/verts_norms.js b/tests/verts_norms/verts_norms.js
index 7123447..d9ee6be 100644
--- a/tests/verts_norms/verts_norms.js
+++ b/tests/verts_norms/verts_norms.js
@@ -1,10 +1,8 @@
var ps, acorn;
function render() {
- ps.translate(0, 0, -20);
-
var c = acorn.getCenter();
- ps.translate(-c[0], -c[1], -c[2]);
+ ps.translate(-c[0], -c[1], -20-c[2]);
ps.clear();
ps.render(acorn);
@@ -17,10 +15,10 @@ function render() {
function start(){
ps = new PointStream();
ps.setup(document.getElementById('canvas'));
+ ps.onRender = render;
ps.background([0, 0, 0, 0.5]);
ps.pointSize(5);
- ps.onRender = render;
acorn = ps.load("../../clouds/acorn_verts_norms.asc");
}
diff --git a/tests/xhr_timing_test/mickey.js b/tests/xhr_timing_test/mickey.js
index ae5792c..af3418c 100644
--- a/tests/xhr_timing_test/mickey.js
+++ b/tests/xhr_timing_test/mickey.js
@@ -3,28 +3,6 @@ var ps, mickey;
var XHR_Timer;
var XHR_TimerDone = false;
-var buttonDown = false;
-var zoomed = -50;
-var rot =[0,0];
-var curCoords = [0,0];
-
-var size = 500;
-
-function zoom(amt){
- zoomed += amt * 2;
- size += amt * 10;
-}
-
-function mousePressed(){
- curCoords[0] = ps.mouseX;
- curCoords[1] = ps.mouseY;
- buttonDown = true;
-}
-
-function mouseReleased(){
- buttonDown = false;
-}
-
function render() {
if(mickey.status === 3){
@@ -32,46 +10,25 @@ function render() {
if(XHR_TimerDone === false){
document.getElementById('XHR_Timer').innerHTML = (new Date() - XHR_Timer)/1000 + " seconds";
XHR_TimerDone = true;
+ ps.onRender = function(){};
}
- var deltaX = ps.mouseX - curCoords[0];
- var deltaY = ps.mouseY - curCoords[1];
-
- if(buttonDown){
- rot[0] += deltaX / 250;
- rot[1] += deltaY / 250;
- curCoords[0] = ps.mouseX;
- curCoords[1] = ps.mouseY;
- }
-
- // transform point cloud
- ps.translate(0, 0, zoomed);
-
- ps.rotateY(rot[0]);
- ps.rotateX(rot[1]);
-
var c = mickey.getCenter();
-
- ps.translate(-c[0], -c[1], -c[2]);
-
- ps.clear();
+ ps.translate(-c[0], -c[1], -50-c[2]);
+
ps.render(mickey);
}
}
function start(){
ps = new PointStream();
-
ps.setup(document.getElementById('canvas'));
+ ps.onRender = render;
ps.pointSize(5);
ps.background([.5, .5, .5, 1]);
+ ps.clear();
- ps.onRender = render;
- ps.onMouseScroll = zoom;
- ps.onMousePressed = mousePressed;
- ps.onMouseReleased = mouseReleased;
-
XHR_Timer = new Date();
mickey = ps.load("../../clouds/mickey.asc");
}
\ No newline at end of file
diff --git a/tutorial/notes.txt b/tutorial/notes.txt
new file mode 100644
index 0000000..ed4445f
--- /dev/null
+++ b/tutorial/notes.txt
@@ -0,0 +1,44 @@
+Using the internal XB PointStream parser and shader
+
+If you decide to use the internal XB PointStream parser and shader, you can have a script displaying your point cloud in about 10 lines of JavaScript. However, you will be required to send in your point cloud as an .ASC file. Also, the built-in shader will only draw the minimum necessary for you point cloud, that is, it will only render vertex positions and colors.
+
+
+
+
+Using the internal XB PointStream parser with a custom shader
+
+If you decide to use the internal .ASC parser and write a custom shader, you'll need to ensure your vertex shader uses the correct uniform and attribute variable names which XB PointStream refers to.
+
+The built-in .ASC parser only reads in vertex position and colors, so you must use the following names to refer to those attributes:
+
+vec3 ps_Vertex
+vec4 ps_Color
+
+XB PointStream will refer to the following uniforms:
+
+For transformations:
+mat4 ps_ModelViewMatrix
+mat4 ps_ProjectionMatrix
+
+For point size:
+float ps_PointSize
+vec3 ps_Attenuation
+
+
+
+
+
+Using the internal XB PointStream shader with a custom parser
+
+If your point cloud is in a format other than .ASC, but you want to use the built-in shader, you'll need to make sure your parser writes to the correct attribute names
+*insert URL to example*
+
+"ps_Vertex"
+"ps_Color"
+
+Your script must also register your parser with XB PointStream with:
+ps.registerParser("XYZ", Your_XYZ_Parser_Name);
+
+
+
+Using a custom shader and parser
\ No newline at end of file
diff --git a/tutorial/parser_template.js b/tutorial/parser_template.js
new file mode 100644
index 0000000..6b7fabe
--- /dev/null
+++ b/tutorial/parser_template.js
@@ -0,0 +1,63 @@
+/*
+*/
+
+var Your_Parser_Name = (function() {
+
+ function Your_Parser_Name(config) {
+
+ this.__defineGetter__("version", function(){
+ return /* !! */;
+ });
+
+ this.__defineGetter__("numParsedPoints", function(){
+ return /* !! */;
+ });
+
+ this.__defineGetter__("numTotalPoints", function(){
+ return /* !! */;
+ });
+
+ this.__defineGetter__("progress", function(){
+ return /* !! */;
+ });
+
+ this.__defineGetter__("fileSize", function(){
+ return /* !! */;
+ });
+
+ /**
+ @param path Path to the resource
+ */
+ this.load = function(path){
+ pathToFile = path;
+
+ AJAX = new XMLHttpRequest();
+
+ AJAX.parser = this;
+
+ AJAX.onloadstart = function(evt){
+ start(AJAX.parser);
+ };
+
+ AJAX.onload = function(evt){
+ end(AJAX.parser);
+ }
+
+ AJAX.parseChunk = function(chunkData){
+ var attributes = {};
+ attributes["ps_Vertex"] = /* !! */;
+ attributes["ps_Color"] = /* !! */;
+
+ parse(AJAX.parser, attributes);
+ };
+
+ AJAX.onprogress = function(evt){
+ };
+
+ // open an asynchronous request to the path
+ AJAX.open("GET", path, true);
+ AJAX.send(null);
+ };
+ }
+ return Your_Parser_Name;
+}());