Open main menu

CDOT Wiki β

Changes

XB PointStream/custom parsers

7,000 bytes added, 15:08, 16 February 2011
no edit summary
===Parser Interface===
 
==Intro==
Currently XBPS only supports reading .ASC file types. If you require the library to render other files, you will need to write a custom parser and register it with the library. This should not be difficult, there are only a few things your parser must implement.
 
===Parser Interface=Example==Here is an example which you can use to help understand the process: [link here]
There will be cases in which users have their own file format
which they want to render with XB PointStream (for example,
.ARA or .XML). We need to give users the ability to write their
own parser and hook it into the library.
Users would write their JavaScript code which would implementthe methods below. Once they do that, they would register theirparser with the library by passing in an extension and their parser.==Parser Skeleton==
The library would then take care following bit of the rest by creating code is a skeleton which you can use as an instanceof their aid to help you write your own parser, call its methods and return a point cloud objectfor XB PointStream.
<pre>
var Your_Parser_Name = (function() { /* The constructor XBPS will create an instance of your parser and pass in an object with three named properties: start - must occur exactly once. When you call this function, pass in a reference to your parser end - must occur exactly once. When you call this function, pass in a reference to your parser parse - may occur one or many times. When you call this function, pass in a reference to your parser as the first argument and an object as the second argument.  This second object must have variables referencing typed single-dimensional arrays which contain the parsed values. For example, if vertsArray and colsArray were Float32Array arrays, you would call the parse function like this:  var attributes = {}; attributes["ps_Vertex"] = vertsArray; attributes["ps_Color"] = colsArray; parse(thisParser, attributes);  PointStream will create buffers using these values and start rendering them using the built-in shaders. Notice the variable names have been qualified with "ps_". If you are using the XB PointStream built-in shaders, you will need to use these exact variable names. These are the only two variables the built-in shaders read. If your parser reads in vertex normal data, you will need to write your own shaders to handle lighting. */ function Your_Parser_Name(config) { /*Returns the version of this parser.*/ this.__defineGetter__("version", function(){return /*!!*/;}); /*Get the number of parsed points so far.*/ this.__defineGetter__("numParsedPoints", function(){return /*!!*/;}); /*Get the total number of points in the point cloud.*/ this.__defineGetter__("numTotalPoints", function(){return /*!!*/;}); /*Returns the progress of downloading the point cloud between zero and one.*/ this.__defineGetter__("progress", function(){return /*!!*/;}); /*Returns the file size of the resource in bytes.*/ this.__defineGetter__("fileSize", function(){return /*!!*/;}); /*Path = path to the resource */ this.load = function(path){/*!!*/}; } return Your_Parser_Name;}());</pre>
@param {Object} obj - collection of named functions== Putting Everything Together ==
These functions pass the === Sample Parser ===Here is a very simple parser which only reads in vertex data from a file.<pre>/*The following is a very simple parser back written only to the library since the library couldbe used as be working with many parsers simultaneouslyan example of how a user could write a parser for XB PointStream.*/var FOO_Parser = (function() {
function FOO_Parser(config) { var start - must occur exactly once= config.start || function(){}; var parse = config.parse || function(){}; var end = config.end || function(){}; var fileSizeInBytes = 0; var numParsedPoints = 0; var numTotalPoints = 0; var progress = 0; // keep track if onprogress event handler was called to // handle Chrome/WebKit vs. Minefield differences. Has // Minefield will call onprogress zero or many times // Chrome/WebKit will call onprogress one argumentor many times var onProgressCalled = false; var AJAX = null; /* Returns the version of this parser. */ this.__defineGetter__("version", function(){return 0.1;}); /* Get the parser itselfnumber of parsed points so far. */ end - must occur exactly once this. Has one argument__defineGetter__("numParsedPoints", function(){return numParsedPoints;}); /* Get the parser itselftotal number of points in the point cloud. */ this.__defineGetter__("numTotalPoints", function(){ return numTotalPoints;}); parse - may occur /* Get the progress of downloading the point cloud (zero to one or many times-1 if unknown) */ this. Has two arguments__defineGetter__("progress", function(){ return progress;}); /* Returns the parser itself and afile size of the resource in bytes. */ named collection of value types this.__defineGetter__("fileSize", function(){return fileSizeInBytes;});
See below for an example /**/ this.load = function(path){
*/Constructor AJAX = new XMLHttpRequest(obj); AJAX.parser = this;
/*occurs exactly once, when the resource begins to be downloaded */ Begins to load AJAX.onloadstart = function(evt){ start(AJAX.parser); }; /*occurs exactly once, when the resourcefile is done being downloaded */ AJAX.onload = function(evt){ var ascData = AJAX.responseText; var chunk = null;
@param // 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){String chunk = ascData; } path - path // otherwise the onprogress event was called at least once, // that means we need to get the data from a specific point to resourcethe end.*/ else if(ascData.length - AJAX.lastNewLineIndex > 1){load chunk = ascData.substring(pathAJAX.lastNewLineIndex, ascData.length); }
AJAX.parseChunk(chunk);
////// Getters numTotalPoints = numParsedPoints; progress = 1; end(AJAX.parser); }
AJAX.parseChunk = function(chunk){ /*/ this occurs over network connections, but not locally. if(chunk !== ""){ // trim leading and trailing spaces chunk = chunk.replace(/\s+$/,""); Get the version of this parser chunk = chunk.replace(/^\s+/,""); // split on white space chunk = chunk.split(/\s+/); @returns {String} parser version * var numVerts = chunk.length/3; numParsedPoints += numVerts; version var verts = new Float32Array(numVerts * 3);
for(var i = 0, j = 0, len = chunk.length; i < len; i += 3, j += 3){ verts[j] = parseFloat(chunk[i]); verts[j+1] = parseFloat(chunk[i+1]); verts[j+2] = parseFloat(chunk[i+2]); } // XB PointStream expects an object with named/value pairs // which contain the attribute arrays. These must match attribute // names found in the shader parse(AJAX.parser, {"ps_Vertex":verts}); } }; /*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; Get the number of points which have been parsed progress = evt.loaded/evt.total; }
@returns {Number} the number of points parsed so far by the parser.*/numParsedPoints onProgressCalled = true;
/*/ if we have something to actually parse Get the total number of points in the point cloud, including points if(AJAX.responseText){ which have not yet been parsed var ascData = AJAX.responseText;
@returns {Number} // likely stopped getting data in the total number middle of points a line in the resource or file: // 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<-1 - 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 unknown(AJAX.readyState === 4){ var chunk = ascData.substring(AJAX.startOfNextChunk, ascData.length); 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); } } }; AJAX.open("GET", path, true); AJAX.send(null); }; } return FOO_Parser;numTotalPoints}());</pre>
/*=== Create your HTML file === Get Create an HTML which includes your parser, the progress of library and the parser, how much it has parsed so fardemo.js script.<pre><html> <head> <script src="foo_parser.js"></script> <script src="xbps.js"></script> <script src="demo.js"></script> </head>
@returns {Number} value between 0 to 1 or -1 if unknown.<body onLoad="start();">* <canvas id="canvas" width="300" height="300"></canvas> progress </body></html></pre>
/*=== Create the Demo.js file === The size of the resource Give XBPS a reference to your parser and tell it what files it can read. In this case, we pass in bytes"foo".
<pre>function start(){ var ps = new PointStream(); ps.setup(document.getElementById('canvas')); ps.registerParser("foo", FOO_Parser); @returns ps.onRender = function render() {Number} the number of bytes in the resource or ps.translate(0, 0, -1 if unknown20); ps.render(acorn); };*/ var acorn = ps.load("pointCloud.foo");fileSize}
</pre>
<pre>
/*
The following example demonstrates how XB PointStream XBPS might use
a particular parser.
*/
// create a hypothetical parser and set the callbacks
parser = new XYZParserYour_Parser_Name({ start: startCallback, parse: parseCallback, end: finishCallback});
// load some resource
parser.load("pointcloud.xyz");
</pre>
1
edit