├── example ├── simpleviewer │ ├── views │ │ ├── layout.ejs │ │ ├── 404.ejs │ │ ├── 500.ejs │ │ ├── webgl.ejs │ │ └── index.ejs │ ├── package.json │ ├── public │ │ ├── stylesheets │ │ │ └── style.css │ │ └── javascripts │ │ │ ├── postprocessing │ │ │ ├── TexturePass.js │ │ │ ├── ShaderPass.js │ │ │ ├── RenderPass.js │ │ │ ├── SavePass.js │ │ │ ├── DotScreenPass.js │ │ │ ├── FilmPass.js │ │ │ ├── MaskPass.js │ │ │ ├── BloomPass.js │ │ │ └── EffectComposer.js │ │ │ ├── Detector.js │ │ │ ├── Stats.js │ │ │ ├── kinect.js │ │ │ ├── main.js │ │ │ ├── webgl.js │ │ │ ├── socket.io.js │ │ │ └── ShaderExtras.js │ └── server.js └── hellokinect │ ├── hellokinect.js │ └── depthbuffer_sample.js ├── .gitignore ├── .npmignore ├── Makefile ├── freenect.js ├── package.json ├── wscript ├── README.md ├── LICENSE └── src └── node_freenect.cc /example/simpleviewer/views/layout.ejs: -------------------------------------------------------------------------------- 1 | <%- body %> 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | .lock-wscript 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | .DS_Store 3 | .lock-wscript 4 | example/ 5 | node_modules/ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | make: 2 | node-waf configure clean build; 3 | 4 | clean: 5 | rm -rf ./build 6 | 7 | -------------------------------------------------------------------------------- /example/simpleviewer/views/404.ejs: -------------------------------------------------------------------------------- 1 |

404 Not Found

2 |

This is not a page you are looking for.

-------------------------------------------------------------------------------- /example/simpleviewer/views/500.ejs: -------------------------------------------------------------------------------- 1 |

500 Internal Server Error

2 |

An unexpected error seems to have occured.

3 |

Error Details

4 |
5 |   <%= error %>
6 | 
7 | -------------------------------------------------------------------------------- /freenect.js: -------------------------------------------------------------------------------- 1 | // require the c++ bindings & export to javascript 2 | var binding = require(__dirname + '/build/default/freenect_binding'); 3 | 4 | var LedOptions = { 5 | OFF: 0, 6 | GREEN: 1, 7 | RED: 2, 8 | YELLOW: 3, 9 | BLINK_GREEN: 5, 10 | BLINK_RED_YELLOW: 6 11 | }; 12 | 13 | module.exports = { 14 | Kinect: binding.Kinect, 15 | LedOptions: LedOptions 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "freenect", 3 | "description" : "libfreenect bindings for Node.js", 4 | "version" : "0.0.2", 5 | "author" : "Kazuyuki Honda ", 6 | "keywords": ["kinect", "libfreenect"], 7 | "repository": "git://github.com/hakobera/node-freenect", 8 | "main" : "freenect", 9 | "scripts" : { 10 | "install" : "node-waf configure build" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/simpleviewer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleviewer", 3 | "description": "A simple node-freenect viewer for kinect with Node.", 4 | "version": "0.0.1", 5 | "homepage": "https://github.com/hakobera/node-freenect", 6 | "author": "Kazuyuki Honda ", 7 | "directories": { 8 | "public": "./public" 9 | }, 10 | "engine": { 11 | "node": ">=-0.4.0" 12 | }, 13 | "dependencies": { 14 | "express": "2.2.2", 15 | "connect": "1.3.0", 16 | "ejs": "0.4.1", 17 | "socket.io": "0.6.17", 18 | "browserify": "0.3.1", 19 | "jsmin": "1.0.0" 20 | }, 21 | "bin": { 22 | "simpleviewer": "./server.js" 23 | } 24 | } -------------------------------------------------------------------------------- /example/hellokinect/hellokinect.js: -------------------------------------------------------------------------------- 1 | var Freenect = require('freenect'); 2 | 3 | var kinect = new Freenect.Kinect(), 4 | ledOption = 0, 5 | prev = Date.now(); 6 | 7 | setInterval(function() { 8 | var now = Date.now(), 9 | interval = now - prev, 10 | depth = kinect.getDepth(), 11 | len = depth.length, 12 | tiltAngle = kinect.getTiltAngle(), 13 | i; 14 | 15 | console.log('Interval: %d, Depth Size: %d, LED Option: %d, Tile Angle: %d', 16 | interval, len, ledOption, tiltAngle); 17 | 18 | // Manupulate depth pixel data like following code. 19 | for (i = 0; i < len; ++i) { 20 | depth[i] = 255 - depth[i]; 21 | } 22 | 23 | // Change LED color and blink pattern. 24 | kinect.setLed(ledOption); 25 | 26 | ledOption += 1; 27 | if (ledOption > 6) { 28 | ledOption = 0 29 | } 30 | 31 | prev = now; 32 | 33 | }, 200); 34 | -------------------------------------------------------------------------------- /example/hellokinect/depthbuffer_sample.js: -------------------------------------------------------------------------------- 1 | var Freenect = require('freenect'); 2 | 3 | var kinect = new Freenect.Kinect(), 4 | ledOption = 0, 5 | prev = Date.now(); 6 | 7 | setInterval(function() { 8 | var now = Date.now(), 9 | interval = now - prev, 10 | depth = kinect.getDepthBuffer(), 11 | len = depth.length, 12 | tiltAngle = kinect.getTiltAngle(), 13 | i; 14 | 15 | console.log('Interval: %d, Depth Size: %d, LED Option: %d, Tile Angle: %d', 16 | interval, len, ledOption, tiltAngle); 17 | 18 | // Manupulate depth pixel data like following code. 19 | for (i = 0; i < len; ++i) { 20 | depth[i] = 255 - depth[i]; 21 | } 22 | 23 | // Change LED color and blink pattern. 24 | kinect.setLed(ledOption); 25 | 26 | ledOption += 1; 27 | if (ledOption > 6) { 28 | ledOption = 0 29 | } 30 | 31 | prev = now; 32 | 33 | }, 100); 34 | -------------------------------------------------------------------------------- /example/simpleviewer/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | color: #fff; 5 | background-color: #000; 6 | font: 14px "Lucida Grande, "Helvetica Nueue", Arial, sans-serif; 7 | } 8 | 9 | h1,h2,h3,h4,h5,h6 10 | p,ul,li,div,form { 11 | margin: 0; 12 | padding: 0; 13 | } 14 | 15 | a { 16 | outline: none; 17 | -moz-outline-style: none; 18 | } 19 | 20 | header { 21 | padding: 0 20px; 22 | color: #000; 23 | background-color: #eee; 24 | } 25 | 26 | #contents { 27 | padding: 10px 20px; 28 | } 29 | 30 | fieldset { 31 | margin: 10px 0; 32 | } 33 | 34 | footer { 35 | margin-top: 15px; 36 | color: #999; 37 | font-size: 12px; 38 | text-align: center; 39 | } 40 | 41 | input.number { 42 | text-align: right; 43 | } 44 | 45 | ul.horizontal { 46 | list-style:: none; 47 | } 48 | 49 | ul.horizontal li { 50 | display: inline-block; 51 | } -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | import os 2 | import Options, Utils 3 | from os import unlink, symlink, chdir, popen 4 | from os.path import exists 5 | 6 | VERSION = '0.0.1' 7 | 8 | def set_options(opt): 9 | opt.tool_options('compiler_cxx') 10 | 11 | def configure(conf): 12 | conf.check_tool('compiler_cxx') 13 | conf.check_tool('node_addon') 14 | conf.check_cxx(lib = 'usb-1.0') 15 | conf.check_cxx(lib = 'freenect') 16 | conf.check_cxx(lib = 'freenect_sync') 17 | 18 | def build(bld): 19 | obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') 20 | obj.target = 'freenect_binding' 21 | obj.source = './src/node_freenect.cc' 22 | obj.includes = [ '/usr/local/include', '/usr/local/include/libfreenect' ] 23 | obj.lib = [ 'usb-1.0', 'freenect', 'freenect_sync' ] 24 | obj.name = 'node-freenect' 25 | 26 | def shutdown(): 27 | t = 'freenect_bindings.node' 28 | if exists('build/default' + t) and not exists(t): 29 | symlink('build/default/' + t, t) 30 | 31 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/TexturePass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.TexturePass = function( texture, opacity ) { 6 | 7 | var shader = THREE.ShaderExtras[ "screen" ]; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | this.uniforms[ "opacity" ].value = ( opacity !== undefined ) ? opacity : 1.0; 12 | this.uniforms[ "tDiffuse" ].texture = texture; 13 | 14 | this.material = new THREE.ShaderMaterial( { 15 | 16 | uniforms: this.uniforms, 17 | vertexShader: shader.vertexShader, 18 | fragmentShader: shader.fragmentShader 19 | 20 | } ); 21 | 22 | this.enabled = true; 23 | this.needsSwap = false; 24 | 25 | }; 26 | 27 | THREE.TexturePass.prototype = { 28 | 29 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 30 | 31 | THREE.EffectComposer.quad.material = this.material; 32 | 33 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer ); 34 | 35 | } 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/ShaderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.ShaderPass = function( shader, textureID ) { 6 | 7 | this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | this.material = new THREE.ShaderMaterial( { 12 | 13 | uniforms: this.uniforms, 14 | vertexShader: shader.vertexShader, 15 | fragmentShader: shader.fragmentShader 16 | 17 | } ); 18 | 19 | this.renderToScreen = false; 20 | 21 | this.enabled = true; 22 | this.needsSwap = true; 23 | this.clear = false; 24 | 25 | }; 26 | 27 | THREE.ShaderPass.prototype = { 28 | 29 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 30 | 31 | if ( this.uniforms[ this.textureID ] ) { 32 | 33 | this.uniforms[ this.textureID ].texture = readBuffer; 34 | 35 | } 36 | 37 | THREE.EffectComposer.quad.material = this.material; 38 | 39 | if ( this.renderToScreen ) { 40 | 41 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); 42 | 43 | } else { 44 | 45 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, this.clear ); 46 | 47 | } 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/RenderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.overrideMaterial = overrideMaterial; 11 | 12 | this.clearColor = clearColor; 13 | this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1; 14 | 15 | this.oldClearColor = new THREE.Color(); 16 | this.oldClearAlpha = 1; 17 | 18 | this.enabled = true; 19 | this.clear = true; 20 | this.needsSwap = false; 21 | 22 | }; 23 | 24 | THREE.RenderPass.prototype = { 25 | 26 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 27 | 28 | this.scene.overrideMaterial = this.overrideMaterial; 29 | 30 | if ( this.clearColor ) { 31 | 32 | this.oldClearColor.copy( renderer.getClearColor() ); 33 | this.oldClearAlpha = renderer.getClearAlpha(); 34 | 35 | renderer.setClearColor( this.clearColor, this.clearAlpha ); 36 | 37 | } 38 | 39 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 40 | 41 | if ( this.clearColor ) { 42 | 43 | renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); 44 | 45 | } 46 | 47 | this.scene.overrideMaterial = null; 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-freenect 2 | ============= 3 | 4 | This software is Node.js addon for control Microsoft Kinect device, 5 | bindings for [libfreenect](https://github.com/OpenKinect/libfreenect). 6 | 7 | 8 | This addon can work on Mac OS X environment, maybe linux environment could work. 9 | 10 | It cannot work on Windows environment. 11 | 12 | Requirements 13 | ------------ 14 | 15 | For the addon, you'll need 16 | 17 | * Mac OS X >= 10.6 18 | * Node.js >= 0.4.0 19 | * libfreenect 20 | * libusb-freenect on Mac OS X, libusb-1.0-dev on Linux 21 | * python >= 2.6 22 | 23 | Installation 24 | ------------ 25 | 26 | Just clone this repository, and using npm. 27 | 28 | npm install 29 | 30 | 31 | Licence 32 | ------- 33 | 34 | Copyright 2011 Kazuyuki Honda 35 | 36 | Licensed under the Apache License, Version 2.0 (the "License"); 37 | you may not use this file except in compliance with the License. 38 | You may obtain a copy of the License at 39 | 40 | http://www.apache.org/licenses/LICENSE-2.0 41 | 42 | Unless required by applicable law or agreed to in writing, software 43 | distributed under the License is distributed on an "AS IS" BASIS, 44 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 45 | See the License for the specific language governing permissions and 46 | limitations under the License. 47 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/SavePass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.SavePass = function( renderTarget ) { 6 | 7 | var shader = THREE.ShaderExtras[ "screen" ]; 8 | 9 | this.textureID = "tDiffuse"; 10 | 11 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 12 | 13 | this.material = new THREE.ShaderMaterial( { 14 | 15 | uniforms: this.uniforms, 16 | vertexShader: shader.vertexShader, 17 | fragmentShader: shader.fragmentShader 18 | 19 | } ); 20 | 21 | this.renderTarget = renderTarget; 22 | 23 | if ( this.renderTarget === undefined ) { 24 | 25 | this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; 26 | this.renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters ); 27 | 28 | } 29 | 30 | this.enabled = true; 31 | this.needsSwap = false; 32 | this.clear = false; 33 | 34 | }; 35 | 36 | THREE.SavePass.prototype = { 37 | 38 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 39 | 40 | if ( this.uniforms[ this.textureID ] ) { 41 | 42 | this.uniforms[ this.textureID ].texture = readBuffer; 43 | 44 | } 45 | 46 | THREE.EffectComposer.quad.material = this.material; 47 | 48 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTarget, this.clear ); 49 | 50 | } 51 | 52 | }; 53 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/DotScreenPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.DotScreenPass = function( center, angle, scale ) { 6 | 7 | var shader = THREE.ShaderExtras[ "dotscreen" ]; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | if ( center !== undefined ) 12 | this.uniforms[ "center" ].value.copy( center ); 13 | 14 | if ( angle !== undefined ) this.uniforms[ "angle"].value = angle; 15 | if ( scale !== undefined ) this.uniforms[ "scale"].value = scale; 16 | 17 | this.material = new THREE.ShaderMaterial( { 18 | 19 | uniforms: this.uniforms, 20 | vertexShader: shader.vertexShader, 21 | fragmentShader: shader.fragmentShader 22 | 23 | } ); 24 | 25 | this.enabled = true; 26 | this.renderToScreen = false; 27 | this.needsSwap = true; 28 | 29 | }; 30 | 31 | THREE.DotScreenPass.prototype = { 32 | 33 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 34 | 35 | this.uniforms[ "tDiffuse" ].texture = readBuffer; 36 | this.uniforms[ "tSize" ].value.set( readBuffer.width, readBuffer.height ); 37 | 38 | THREE.EffectComposer.quad.material = this.material; 39 | 40 | if ( this.renderToScreen ) { 41 | 42 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); 43 | 44 | } else { 45 | 46 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, false ); 47 | 48 | } 49 | 50 | } 51 | 52 | }; 53 | -------------------------------------------------------------------------------- /example/simpleviewer/views/webgl.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple Viewer - node-freenect 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/FilmPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.FilmPass = function( noiseIntensity, scanlinesIntensity, scanlinesCount, grayscale ) { 6 | 7 | var shader = THREE.ShaderExtras[ "film" ]; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | this.material = new THREE.ShaderMaterial( { 12 | 13 | uniforms: this.uniforms, 14 | vertexShader: shader.vertexShader, 15 | fragmentShader: shader.fragmentShader 16 | 17 | } ); 18 | 19 | if ( grayscale !== undefined ) this.uniforms.grayscale.value = grayscale; 20 | if ( noiseIntensity !== undefined ) this.uniforms.nIntensity.value = noiseIntensity; 21 | if ( scanlinesIntensity !== undefined ) this.uniforms.sIntensity.value = scanlinesIntensity; 22 | if ( scanlinesCount !== undefined ) this.uniforms.sCount.value = scanlinesCount; 23 | 24 | this.enabled = true; 25 | this.renderToScreen = false; 26 | this.needsSwap = true; 27 | 28 | }; 29 | 30 | THREE.FilmPass.prototype = { 31 | 32 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 33 | 34 | this.uniforms[ "tDiffuse" ].texture = readBuffer; 35 | this.uniforms[ "time" ].value += delta; 36 | 37 | THREE.EffectComposer.quad.material = this.material; 38 | 39 | if ( this.renderToScreen ) { 40 | 41 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); 42 | 43 | } else { 44 | 45 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, false ); 46 | 47 | } 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/MaskPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.MaskPass = function ( scene, camera ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.enabled = true; 11 | this.clear = true; 12 | this.needsSwap = false; 13 | 14 | this.inverse = false; 15 | 16 | }; 17 | 18 | THREE.MaskPass.prototype = { 19 | 20 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 21 | 22 | var context = renderer.context; 23 | 24 | // don't update color or depth 25 | 26 | context.colorMask( false, false, false, false ); 27 | context.depthMask( false ); 28 | 29 | // set up stencil 30 | 31 | var writeValue, clearValue; 32 | 33 | if ( this.inverse ) { 34 | 35 | writeValue = 0; 36 | clearValue = 1; 37 | 38 | } else { 39 | 40 | writeValue = 1; 41 | clearValue = 0; 42 | 43 | } 44 | 45 | context.enable( context.STENCIL_TEST ); 46 | context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE ); 47 | context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff ); 48 | context.clearStencil( clearValue ); 49 | 50 | // draw into the stencil buffer 51 | 52 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 53 | renderer.render( this.scene, this.camera, writeBuffer, this.clear ); 54 | 55 | // re-enable update of color and depth 56 | 57 | context.colorMask( true, true, true, true ); 58 | context.depthMask( true ); 59 | 60 | // only render where stencil is set to 1 61 | 62 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1 63 | context.stencilOp( context.KEEP, context.KEEP, context.KEEP ); 64 | 65 | } 66 | 67 | }; 68 | 69 | 70 | THREE.ClearMaskPass = function () { 71 | 72 | this.enabled = true; 73 | 74 | }; 75 | 76 | THREE.ClearMaskPass.prototype = { 77 | 78 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 79 | 80 | var context = renderer.context; 81 | 82 | context.disable( context.STENCIL_TEST ); 83 | 84 | } 85 | 86 | }; 87 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/Detector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author mr.doob / http://mrdoob.com/ 4 | */ 5 | 6 | Detector = { 7 | 8 | canvas: !! window.CanvasRenderingContext2D, 9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), 10 | workers: !! window.Worker, 11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob, 12 | 13 | getWebGLErrorMessage: function () { 14 | 15 | var element = document.createElement( 'div' ); 16 | element.id = 'webgl-error-message'; 17 | element.style.fontFamily = 'monospace'; 18 | element.style.fontSize = '13px'; 19 | element.style.fontWeight = 'normal'; 20 | element.style.textAlign = 'center'; 21 | element.style.background = '#fff'; 22 | element.style.color = '#000'; 23 | element.style.padding = '1.5em'; 24 | element.style.width = '400px'; 25 | element.style.margin = '5em auto 0'; 26 | 27 | if ( ! this.webgl ) { 28 | 29 | element.innerHTML = window.WebGLRenderingContext ? [ 30 | 'Your graphics card does not seem to support WebGL.
', 31 | 'Find out how to get it here.' 32 | ].join( '\n' ) : [ 33 | 'Your browser does not seem to support WebGL.
', 34 | 'Find out how to get it here.' 35 | ].join( '\n' ); 36 | 37 | } 38 | 39 | return element; 40 | 41 | }, 42 | 43 | addGetWebGLMessage: function ( parameters ) { 44 | 45 | var parent, id, element; 46 | 47 | parameters = parameters || {}; 48 | 49 | parent = parameters.parent !== undefined ? parameters.parent : document.body; 50 | id = parameters.id !== undefined ? parameters.id : 'oldie'; 51 | 52 | element = Detector.getWebGLErrorMessage(); 53 | element.id = id; 54 | 55 | parent.appendChild( element ); 56 | 57 | } 58 | 59 | }; 60 | -------------------------------------------------------------------------------- /example/simpleviewer/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple Viewer - node-freenect 6 | 7 | 8 | 9 |
10 |

Simple Viewer

11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | Image Control 25 |
26 | 27 | 28 | 29 | Wait... 30 |
31 |
32 | 33 | 34 |
35 |
36 |
37 | LED Control 38 |
39 |
    40 |
  • 41 |
  • 42 |
  • 43 |
  • 44 |
  • 45 |
  • 46 |
47 |
48 |
49 |
50 | Tilt Angle Control 51 |
52 | 53 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 |
67 |

Source Code is availabe on github

68 |

©2011 hakobera

69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/Stats.js: -------------------------------------------------------------------------------- 1 | // stats.js r8 - http://github.com/mrdoob/stats.js 2 | var Stats=function(){var h,a,n=0,o=0,i=Date.now(),u=i,p=i,l=0,q=1E3,r=0,e,j,f,b=[[16,16,48],[0,255,255]],m=0,s=1E3,t=0,d,k,g,c=[[16,48,16],[0,255,0]];h=document.createElement("div");h.style.cursor="pointer";h.style.width="80px";h.style.opacity="0.9";h.style.zIndex="10001";h.addEventListener("mousedown",function(a){a.preventDefault();n=(n+1)%2;n==0?(e.style.display="block",d.style.display="none"):(e.style.display="none",d.style.display="block")},!1);e=document.createElement("div");e.style.textAlign= 3 | "left";e.style.lineHeight="1.2em";e.style.backgroundColor="rgb("+Math.floor(b[0][0]/2)+","+Math.floor(b[0][1]/2)+","+Math.floor(b[0][2]/2)+")";e.style.padding="0 0 3px 3px";h.appendChild(e);j=document.createElement("div");j.style.fontFamily="Helvetica, Arial, sans-serif";j.style.fontSize="9px";j.style.color="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";j.style.fontWeight="bold";j.innerHTML="FPS";e.appendChild(j);f=document.createElement("div");f.style.position="relative";f.style.width="74px";f.style.height= 4 | "30px";f.style.backgroundColor="rgb("+b[1][0]+","+b[1][1]+","+b[1][2]+")";for(e.appendChild(f);f.children.length<74;)a=document.createElement("span"),a.style.width="1px",a.style.height="30px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+b[0][0]+","+b[0][1]+","+b[0][2]+")",f.appendChild(a);d=document.createElement("div");d.style.textAlign="left";d.style.lineHeight="1.2em";d.style.backgroundColor="rgb("+Math.floor(c[0][0]/2)+","+Math.floor(c[0][1]/2)+","+Math.floor(c[0][2]/2)+")";d.style.padding= 5 | "0 0 3px 3px";d.style.display="none";h.appendChild(d);k=document.createElement("div");k.style.fontFamily="Helvetica, Arial, sans-serif";k.style.fontSize="9px";k.style.color="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";k.style.fontWeight="bold";k.innerHTML="MS";d.appendChild(k);g=document.createElement("div");g.style.position="relative";g.style.width="74px";g.style.height="30px";g.style.backgroundColor="rgb("+c[1][0]+","+c[1][1]+","+c[1][2]+")";for(d.appendChild(g);g.children.length<74;)a=document.createElement("span"), 6 | a.style.width="1px",a.style.height=Math.random()*30+"px",a.style.cssFloat="left",a.style.backgroundColor="rgb("+c[0][0]+","+c[0][1]+","+c[0][2]+")",g.appendChild(a);return{domElement:h,update:function(){i=Date.now();m=i-u;s=Math.min(s,m);t=Math.max(t,m);k.textContent=m+" MS ("+s+"-"+t+")";var a=Math.min(30,30-m/200*30);g.appendChild(g.firstChild).style.height=a+"px";u=i;o++;if(i>p+1E3)l=Math.round(o*1E3/(i-p)),q=Math.min(q,l),r=Math.max(r,l),j.textContent=l+" FPS ("+q+"-"+r+")",a=Math.min(30,30-l/ 7 | 100*30),f.appendChild(f.firstChild).style.height=a+"px",p=i,o=0}}}; 8 | 9 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/kinect.js: -------------------------------------------------------------------------------- 1 | (function(global) { 2 | var server, 3 | socket, 4 | host = 'localhost', 5 | port = 3000, 6 | connected = false, 7 | connectionCallback, 8 | commandCallbacks = {}; 9 | 10 | socket = new io.Socket(host, { 11 | port: port, 12 | connectTimeout: 10000, 13 | reconnect: true 14 | }); 15 | 16 | socket.on('connecting', function(transportType) { 17 | connected = false; 18 | console.log('Connecting to %s:%d using %s', host, port, transportType); 19 | }); 20 | 21 | socket.on('connect', function() { 22 | connected = true; 23 | console.log('Connected to %s:%d', host, port); 24 | if (connectionCallback) { 25 | connectionCallback(); 26 | } 27 | }); 28 | 29 | socket.on('connect_failed', function() { 30 | connected = false; 31 | console.log('Connect failed.'); 32 | }); 33 | 34 | socket.on('close', function() { 35 | connected = false; 36 | console.log('Connection closed.'); 37 | }); 38 | 39 | socket.on('disconnect', function() { 40 | connected = false; 41 | console.log('Connection disconnected.'); 42 | }); 43 | 44 | socket.on('recconect', function(transportType, reconnectionAttempts) { 45 | connected = true; 46 | console.log('Reconnecting to %s:%d using %s %s', host, port, transportType, reconnectionAttempts); 47 | }); 48 | 49 | socket.on('reconnect_failed', function() { 50 | connected = false; 51 | console.log('Reconnect failed.'); 52 | }); 53 | 54 | socket.on('message', function(command) { 55 | var cmd = JSON.parse(command); 56 | // console.log('[callback][%s]', cmd.type); 57 | if (commandCallbacks.hasOwnProperty(cmd.type)) { 58 | commandCallbacks[cmd.type].call(Kinect, cmd.result); 59 | }; 60 | }); 61 | 62 | Kinect = { 63 | 64 | connect: function(callback) { 65 | socket.connect(); 66 | if (callback && typeof(callback) === 'function') { 67 | connectionCallback = callback 68 | } 69 | }, 70 | 71 | sendCommand: function(commandType, options) { 72 | if (connected) { 73 | var cmd = options || {}; 74 | cmd.type = commandType 75 | // console.log('[send][%s]', cmd.type, cmd); 76 | socket.send(JSON.stringify(cmd)); 77 | } 78 | }, 79 | 80 | on: function(commandType, callback) { 81 | if (callback && typeof(callback) === 'function') { 82 | commandCallbacks[commandType] = callback; 83 | } 84 | }, 85 | 86 | setLed: function(ledOption) { 87 | this.sendCommand('setLed', { option: ledOption }); 88 | }, 89 | 90 | setTiltAngle: function(angle) { 91 | this.sendCommand('setTiltAngle', { angle: angle }); 92 | }, 93 | 94 | getDepth: function(callback) { 95 | this.sendCommand('getDepth'); 96 | this.on('getDepth', function(ret) { 97 | if (callback) { 98 | callback.call(Kinect, ret.data); 99 | } 100 | }); 101 | }, 102 | 103 | getVideo: function(callback) { 104 | this.sendCommand('getVideo'); 105 | this.on('getVideo', function(ret) { 106 | if (callback) { 107 | callback.call(Kinect, ret.data); 108 | } 109 | }); 110 | }, 111 | 112 | stop: function() { 113 | this.sendCommand('stop'); 114 | } 115 | 116 | }; 117 | 118 | Kinect.LED_OPTIONS = { 119 | OFF: 0, 120 | GREEN: 1, 121 | RED: 2, 122 | YELLOW: 3, 123 | BLINK_GREEN: 5, 124 | BLINK_RED_YELLOW: 6 125 | }; 126 | 127 | return Kinect; 128 | })(this); -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/BloomPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.BloomPass = function( strength, kernelSize, sigma, resolution ) { 6 | 7 | strength = ( strength !== undefined ) ? strength : 1; 8 | kernelSize = ( kernelSize !== undefined ) ? kernelSize : 25; 9 | sigma = ( sigma !== undefined ) ? sigma : 4.0; 10 | resolution = ( resolution !== undefined ) ? resolution : 256; 11 | 12 | // render targets 13 | 14 | var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat }; 15 | 16 | this.renderTargetX = new THREE.WebGLRenderTarget( resolution, resolution, pars ); 17 | this.renderTargetY = new THREE.WebGLRenderTarget( resolution, resolution, pars ); 18 | 19 | // screen material 20 | 21 | var screenShader = THREE.ShaderExtras[ "screen" ]; 22 | 23 | this.screenUniforms = THREE.UniformsUtils.clone( screenShader.uniforms ); 24 | 25 | this.screenUniforms[ "opacity" ].value = strength; 26 | 27 | this.materialScreen = new THREE.ShaderMaterial( { 28 | 29 | uniforms: this.screenUniforms, 30 | vertexShader: screenShader.vertexShader, 31 | fragmentShader: screenShader.fragmentShader, 32 | blending: THREE.AdditiveBlending, 33 | transparent: true 34 | 35 | } ); 36 | 37 | // convolution material 38 | 39 | var convolutionShader = THREE.ShaderExtras[ "convolution" ]; 40 | 41 | this.convolutionUniforms = THREE.UniformsUtils.clone( convolutionShader.uniforms ); 42 | 43 | this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurx; 44 | this.convolutionUniforms[ "cKernel" ].value = THREE.ShaderExtras.buildKernel( sigma ); 45 | 46 | this.materialConvolution = new THREE.ShaderMaterial( { 47 | 48 | uniforms: this.convolutionUniforms, 49 | vertexShader: "#define KERNEL_SIZE " + kernelSize + ".0\n" + convolutionShader.vertexShader, 50 | fragmentShader: "#define KERNEL_SIZE " + kernelSize + "\n" + convolutionShader.fragmentShader 51 | 52 | } ); 53 | 54 | this.enabled = true; 55 | this.needsSwap = false; 56 | this.clear = false; 57 | 58 | }; 59 | 60 | THREE.BloomPass.prototype = { 61 | 62 | render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) { 63 | 64 | if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST ); 65 | 66 | // Render quad with blured scene into texture (convolution pass 1) 67 | 68 | THREE.EffectComposer.quad.material = this.materialConvolution; 69 | 70 | this.convolutionUniforms[ "tDiffuse" ].texture = readBuffer; 71 | this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX; 72 | 73 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetX, true ); 74 | 75 | 76 | // Render quad with blured scene into texture (convolution pass 2) 77 | 78 | this.convolutionUniforms[ "tDiffuse" ].texture = this.renderTargetX; 79 | this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurY; 80 | 81 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTargetY, true ); 82 | 83 | // Render original scene with superimposed blur to texture 84 | 85 | THREE.EffectComposer.quad.material = this.materialScreen; 86 | 87 | this.screenUniforms[ "tDiffuse" ].texture = this.renderTargetY; 88 | 89 | if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST ); 90 | 91 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, readBuffer, this.clear ); 92 | 93 | } 94 | 95 | }; 96 | 97 | THREE.BloomPass.blurX = new THREE.Vector2( 0.001953125, 0.0 ); 98 | THREE.BloomPass.blurY = new THREE.Vector2( 0.0, 0.001953125 ); 99 | 100 | 101 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/main.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | var rgbButton = $('#rbgButton'), 3 | depthButton = $('#depthButton'), 4 | stopButton = $('#stopButton'), 5 | depthCanvas = document.getElementById('depthbuffer'), 6 | depthContext = depthCanvas.getContext('2d'), 7 | // screenImage = screenContext.createImageData(screenCanvas.width, screenCanvas.height), 8 | depthImage = depthContext.createImageData(80, 60), 9 | depthSize = depthCanvas.width * depthCanvas.height, 10 | 11 | screenCanvas = document.getElementById('screen'), 12 | screenContext = screenCanvas.getContext('2d'), 13 | // screenImage = screenContext.createImageData(screenCanvas.width, screenCanvas.height), 14 | screenImage = screenContext.createImageData(400, 300), 15 | screenSize = screenCanvas.width * screenCanvas.height, 16 | 17 | ledSwitch = $('input[name=led]'), 18 | tiltAngleInput = $('#tiltAngleInput'), 19 | tiltAngleButton = $('#tiltAngleButton'); 20 | 21 | Kinect.connect(); 22 | /* 23 | rgbButton.click(function(e) { 24 | e.preventDefault(); 25 | Kinect.getVideo(function(data) { 26 | var length = data.length, 27 | pixels = screenImage.data, 28 | i, srcIndex, dstIndex; 29 | 30 | console.log(length); 31 | 32 | for (i = 0; i < screenSize; i+=4) { 33 | srcIndex = i * 3; 34 | dstIndex = i * 4; 35 | pixels[dstIndex ] = data[srcIndex ]; 36 | pixels[dstIndex+1] = data[srcIndex+1]; 37 | pixels[dstIndex+2] = data[srcIndex+2]; 38 | pixels[dstIndex+3] = 255; 39 | } 40 | 41 | screenContext.putImageData(screenImage, 0, 0); 42 | }); 43 | }); 44 | */ 45 | 46 | 47 | var last_frametime = 0; 48 | var last_fps = 0; 49 | 50 | var getDepthFrame = function() { 51 | 52 | Kinect.getDepth(function(data) { 53 | console.log(data); 54 | 55 | var offset = 0, 56 | length = data.length, 57 | pixels = depthImage.data, 58 | i, color; 59 | 60 | offset = 0; 61 | for (i = 0; i < length; ++i) { 62 | color = data[i] ; 63 | pixels[offset ] = color; 64 | pixels[offset+1] = color; 65 | pixels[offset+2] = color; 66 | pixels[offset+3] = 255; 67 | offset += 4; 68 | } 69 | depthContext.putImageData(depthImage, 0, 0); 70 | screenContext.drawImage(depthCanvas, 0,0,depthCanvas.width,depthCanvas.height,0,0,screenCanvas.width,screenCanvas.height); 71 | 72 | var t = (new Date()).getTime(); 73 | if (last_frametime == 0) 74 | last_frametime = t; 75 | 76 | var dt = t - last_frametime; 77 | if( dt >0 ){ 78 | var cfps = 1000.0 / dt; 79 | 80 | last_fps *= 0.5; 81 | last_fps += cfps*0.5; 82 | } 83 | 84 | $('#debug').text('avg. fps: '+Math.round(last_fps,3)); 85 | 86 | last_frametime = t; 87 | getDepthFrame(); 88 | }); 89 | }; 90 | 91 | setTimeout(function(){ 92 | getDepthFrame(); 93 | }, 500); 94 | 95 | /* 96 | depthButton.click(function(e) { 97 | e.preventDefault(); 98 | Kinect.getDepth(function(data) { 99 | var offset = 0, 100 | length = data.length, 101 | pixels = screenImage.data, 102 | scale = 255 / 2047, 103 | i, color; 104 | 105 | for (i = 0; i < length; ++i) { 106 | offset = 4 * i; 107 | color = data[i] * scale | 0; 108 | pixels[offset ] = color; 109 | pixels[offset+1] = color; 110 | pixels[offset+2] = color; 111 | pixels[offset+3] = 255; 112 | } 113 | 114 | screenContext.putImageData(screenImage, 0, 0); 115 | }); 116 | }); 117 | 118 | stopButton.click(function(e) { 119 | e.preventDefault(); 120 | Kinect.stop(); 121 | }); 122 | */ 123 | ledSwitch.click(function(e) { 124 | Kinect.setLed($(this).val()); 125 | }); 126 | 127 | tiltAngleButton.click(function(e) { 128 | e.preventDefault(); 129 | var v = tiltAngleInput.val(), 130 | angle = parseFloat(v); 131 | if (!isNaN(angle)) { 132 | Kinect.setTiltAngle(angle); 133 | } 134 | }); 135 | 136 | }); 137 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/postprocessing/EffectComposer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.EffectComposer = function( renderer, renderTarget ) { 6 | 7 | this.renderer = renderer; 8 | 9 | this.renderTarget1 = renderTarget; 10 | 11 | if ( this.renderTarget1 === undefined ) { 12 | 13 | this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; 14 | this.renderTarget1 = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters ); 15 | 16 | } 17 | 18 | this.renderTarget2 = this.renderTarget1.clone(); 19 | 20 | this.writeBuffer = this.renderTarget1; 21 | this.readBuffer = this.renderTarget2; 22 | 23 | this.passes = []; 24 | 25 | this.copyPass = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] ); 26 | 27 | }; 28 | 29 | THREE.EffectComposer.prototype = { 30 | 31 | swapBuffers: function() { 32 | 33 | var tmp = this.readBuffer; 34 | this.readBuffer = this.writeBuffer; 35 | this.writeBuffer = tmp; 36 | 37 | }, 38 | 39 | addPass: function ( pass ) { 40 | 41 | this.passes.push( pass ); 42 | 43 | }, 44 | 45 | render: function ( delta ) { 46 | 47 | this.writeBuffer = this.renderTarget1; 48 | this.readBuffer = this.renderTarget2; 49 | 50 | var maskActive = false; 51 | 52 | var pass, i, il = this.passes.length; 53 | 54 | for ( i = 0; i < il; i ++ ) { 55 | 56 | pass = this.passes[ i ]; 57 | 58 | if ( !pass.enabled ) continue; 59 | 60 | pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive ); 61 | 62 | if ( pass.needsSwap ) { 63 | 64 | if ( maskActive ) { 65 | 66 | var context = this.renderer.context; 67 | 68 | context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff ); 69 | 70 | this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta ); 71 | 72 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); 73 | 74 | } 75 | 76 | this.swapBuffers(); 77 | 78 | } 79 | 80 | if ( pass instanceof THREE.MaskPass ) { 81 | 82 | maskActive = true; 83 | 84 | } else if ( pass instanceof THREE.ClearMaskPass ) { 85 | 86 | maskActive = false; 87 | 88 | } 89 | 90 | } 91 | 92 | }, 93 | 94 | reset: function ( renderTarget ) { 95 | 96 | this.renderTarget1 = renderTarget; 97 | 98 | if ( this.renderTarget1 === undefined ) { 99 | 100 | this.renderTarget1 = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters ); 101 | 102 | } 103 | 104 | this.renderTarget2 = this.renderTarget1.clone(); 105 | 106 | this.writeBuffer = this.renderTarget1; 107 | this.readBuffer = this.renderTarget2; 108 | 109 | THREE.EffectComposer.quad.scale.set( window.innerWidth, window.innerHeight, 1 ); 110 | 111 | THREE.EffectComposer.camera.left = window.innerWidth / - 2; 112 | THREE.EffectComposer.camera.right = window.innerWidth / 2; 113 | THREE.EffectComposer.camera.top = window.innerHeight / 2; 114 | THREE.EffectComposer.camera.bottom = window.innerHeight / - 2; 115 | 116 | THREE.EffectComposer.camera.updateProjectionMatrix(); 117 | 118 | } 119 | 120 | }; 121 | 122 | // shared ortho camera 123 | 124 | THREE.EffectComposer.camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -10000, 10000 ); 125 | 126 | // shared fullscreen quad scene 127 | 128 | THREE.EffectComposer.geometry = new THREE.PlaneGeometry( 1, 1 ); 129 | 130 | THREE.EffectComposer.quad = new THREE.Mesh( THREE.EffectComposer.geometry, null ); 131 | THREE.EffectComposer.quad.position.z = -100; 132 | THREE.EffectComposer.quad.scale.set( window.innerWidth, window.innerHeight, 1 ); 133 | 134 | THREE.EffectComposer.scene = new THREE.Scene(); 135 | THREE.EffectComposer.scene.add( THREE.EffectComposer.quad ); 136 | THREE.EffectComposer.scene.add( THREE.EffectComposer.camera ); 137 | -------------------------------------------------------------------------------- /example/simpleviewer/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | connect = require('connect'), 3 | ejs = require('ejs'), 4 | sys = require('sys'), 5 | path = require('path'), 6 | io = require('socket.io'), 7 | freenect = require('../../freenect'), 8 | kinect = new freenect.Kinect(), 9 | port = 3000, 10 | app, 11 | socket; 12 | 13 | app = express.createServer(); 14 | 15 | app.configure(function() { 16 | app.set('views', __dirname + '/views'); 17 | app.use(express.favicon()); 18 | app.use(express.bodyParser()); 19 | app.use(express.cookieParser()); 20 | app.use(express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b]0m :response-time ms' })); 21 | app.use(express.methodOverride()); 22 | app.use(express.static(__dirname + '/public')); 23 | }); 24 | 25 | app.configure('development', function() { 26 | app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 27 | }); 28 | 29 | app.configure('production', function() { 30 | app.use(express.errorHandler()); 31 | }); 32 | 33 | function NotFound(msg) { 34 | this.name = 'NotFound'; 35 | Error.call(this, msg); 36 | Error.captureStackTrace(this, arguments.callee); 37 | } 38 | 39 | sys.inherits(NotFound, Error); 40 | 41 | app.get('/404', function(req, res) { 42 | throw new NotFound(); 43 | }); 44 | 45 | app.get('/500', function(req, res) { 46 | throw new Error('An expected error'); 47 | }); 48 | 49 | app.get('/bad', function(req, res) { 50 | unknownMethod(); 51 | }); 52 | 53 | app.error(function(err, req, res, next) { 54 | if (err instanceof NotFound) { 55 | res.render('404.ejs', { status: 404 }); 56 | } else { 57 | next(err); 58 | } 59 | }); 60 | 61 | if (app.settings.env === 'production') { 62 | app.error(function(err, req, res) { 63 | res.render('500.ejs', { 64 | status: 500, 65 | locals: { 66 | error: err 67 | } 68 | }); 69 | }); 70 | } 71 | 72 | app.get('/', function(req, res) { 73 | res.render('index.ejs'); 74 | }); 75 | 76 | app.get('/webgl', function(req, res) { 77 | res.render('webgl.ejs'); 78 | }); 79 | 80 | var commands = { 81 | setLed: function(cmd) { 82 | var option = parseInt(cmd.option, 10); 83 | if (isNaN(option)) { 84 | color = 5; // BLINK GREEN 85 | } 86 | return kinect.setLed(option); 87 | }, 88 | 89 | setTiltAngle: function(cmd) { 90 | var angle = parseFloat(cmd.angle); 91 | if (isNaN(angle)) { 92 | return false; 93 | } 94 | return kinect.setTiltAngle(angle); 95 | }, 96 | 97 | stop: function(cmd) { 98 | kinect.stop(); 99 | return true; 100 | }, 101 | 102 | getDepth: function(cmd) { 103 | var buffer = kinect.getScaledDepthBuffer(80,60); 104 | d = Array.prototype.slice.call(buffer,0); 105 | // console.log('Buffer:', d); 106 | return { 107 | data: d 108 | }; 109 | }, 110 | 111 | getVideo: function(cmd) { 112 | var buffer = kinect.getVideo(); 113 | return { 114 | data: buffer 115 | }; 116 | } 117 | 118 | }; 119 | 120 | app.listen(port); 121 | console.log('Express server listening on port %d, environment: %s', port, app.settings.env); 122 | console.log('Using connect %s, Express %s, EJS %s', connect.version, express.version, ejs.version); 123 | 124 | socket = io.listen(app); 125 | 126 | /* 127 | app.configure('production',function(){ 128 | socket.set('transports', [ 129 | 'websocket' 130 | //,flashsocket' 131 | //,'htmlfile' 132 | //,'xhr-polling' 133 | //,'jsonp-polling' 134 | ]); 135 | }); 136 | */ 137 | 138 | socket.on('connection', function(client) { 139 | console.log('Connected from'); 140 | console.log(client); 141 | 142 | client.on('message', function(message) { 143 | var command = JSON.parse(message), 144 | ret = {}; 145 | 146 | // console.log(command); 147 | if (commands.hasOwnProperty(command.type)) { 148 | ret.type = command.type; 149 | ret.result = commands[command.type](command); 150 | client.send(JSON.stringify(ret)); 151 | } else { 152 | ret.type = command.type; 153 | ret.result = 'Invalid command.'; 154 | client.send(JSON.stringify(ret)); 155 | } 156 | }); 157 | 158 | client.on('disconnect', function() { 159 | console.log('Disconnect %s', client); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/webgl.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | var depthCanvas = document.getElementById('depthbuffer'), 4 | depthContext = depthCanvas.getContext('2d'), 5 | depthImage = depthContext.createImageData(80, 60), 6 | depthSize = depthCanvas.width * depthCanvas.height, 7 | 8 | screenCanvas = document.getElementById('screen'), 9 | screenContext = screenCanvas.getContext('2d'), 10 | screenImage = screenContext.createImageData(400, 300), 11 | screenSize = screenCanvas.width * screenCanvas.height; 12 | 13 | Kinect.connect(); 14 | 15 | var last_frametime = 0; 16 | var last_fps = 0; 17 | 18 | var getDepthFrame = function() { 19 | 20 | Kinect.getDepth(function(data) { 21 | // console.log(data); 22 | 23 | var offset = 0, 24 | length = data.length, 25 | pixels = depthImage.data, 26 | i, color; 27 | 28 | offset = 0; 29 | for (i = 0; i < length; ++i) { 30 | color = data[i]; 31 | if (color < 5) color = 255; 32 | pixels[offset ] = color; 33 | pixels[offset+1] = color; 34 | pixels[offset+2] = color; 35 | pixels[offset+3] = 255; 36 | offset += 4; 37 | } 38 | depthContext.putImageData(depthImage, 0, 0); 39 | screenContext.drawImage(depthCanvas, 0,0,depthCanvas.width,depthCanvas.height,0,0,screenCanvas.width,screenCanvas.height); 40 | updateBlockZ(); 41 | 42 | var t = (new Date()).getTime(); 43 | if (last_frametime == 0) 44 | last_frametime = t; 45 | 46 | var dt = t - last_frametime; 47 | if( dt >0 ){ 48 | var cfps = 1000.0 / dt; 49 | 50 | last_fps *= 0.5; 51 | last_fps += cfps*0.5; 52 | } 53 | 54 | $('#debug').text('avg. fps: '+Math.round(last_fps,3)); 55 | 56 | last_frametime = t; 57 | 58 | getDepthFrame(); 59 | }); 60 | }; 61 | 62 | 63 | 64 | 65 | 66 | 67 | var container, stats; 68 | var camera, scene, projector, renderer; 69 | var objects = [], plane; 70 | 71 | var delta = 0.01; 72 | 73 | 74 | var gridwidth = 38; 75 | var gridheight = 24; 76 | var gridlength = gridwidth * gridheight; 77 | 78 | var objectspacing = 40; 79 | 80 | var mouse = new THREE.Vector2(), 81 | offset = new THREE.Vector3(), 82 | INTERSECTED, 83 | SELECTED; 84 | 85 | var halfWidth, halfHeight; 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | function init() { 101 | 102 | var halfWidth = window.innerWidth / 2; 103 | var halfHeight = window.innerHeight / 2; 104 | 105 | container = document.getElementById('webgl'); 106 | 107 | scene = new THREE.Scene(); 108 | 109 | camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10000 ); 110 | camera.position.z = 1000; 111 | camera.position.x = 0; 112 | scene.add( camera ); 113 | 114 | scene.add( new THREE.AmbientLight( 0x505050 ) ); 115 | 116 | var light = new THREE.SpotLight( 0xffffff, 1 ); 117 | light.position.set( -1000, 800, 2500 ); 118 | light.castShadow = true; 119 | light.shadowCameraNear = 200; 120 | light.shadowCameraFar = camera.far; 121 | light.shadowCameraFov = 50; 122 | light.shadowBias = -0.00022; 123 | light.shadowDarkness = 0.8; 124 | light.shadowMapWidth = 512; 125 | light.shadowMapHeight = 512; 126 | 127 | scene.add( light ); 128 | 129 | var geometry = new THREE.CubeGeometry( objectspacing*0.8, objectspacing*0.8, 800 ); 130 | 131 | for ( var i = 0; i < gridlength; i ++ ) { 132 | 133 | // var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) ); 134 | var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0xffffff } ) ); 135 | 136 | object.material.ambient = object.material.color; 137 | 138 | var row = Math.floor( i / gridwidth ); 139 | var col = Math.floor( i % gridwidth ); 140 | 141 | object.position.x = -objectspacing * (col - (gridwidth-1)/2); 142 | object.position.y = -objectspacing * (row - (gridheight-1)/2); 143 | object.position.z = 0; 144 | 145 | object.rotation.x = 0;// ( Math.random() * 360 ) * Math.PI / 180; 146 | object.rotation.y = 0;// ( Math.random() * 360 ) * Math.PI / 180; 147 | object.rotation.z = 0;// ( Math.random() * 360 ) * Math.PI / 180; 148 | 149 | object.castShadow = true; 150 | object.receiveShadow = true; 151 | 152 | scene.add( object ); 153 | 154 | objects.push( object ); 155 | 156 | } 157 | 158 | // plane = new THREE.Mesh( new THREE.PlaneGeometry( 2000, 2000, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) ); 159 | // plane.lookAt( camera.position ); 160 | // plane.visible = false; 161 | // scene.add( plane ); 162 | 163 | projector = new THREE.Projector(); 164 | 165 | renderer = new THREE.WebGLRenderer( { antialias: false } ); 166 | renderer.sortObjects = false; 167 | renderer.setSize( window.innerWidth, window.innerHeight ); 168 | renderer.shadowMapEnabled = true; 169 | renderer.shadowMapSoft = false; 170 | 171 | var shaderVignette = THREE.ShaderExtras[ "vignette" ]; 172 | var effectVignette = new THREE.ShaderPass( shaderVignette ); 173 | effectVignette.uniforms[ "offset" ].value = 0.95; 174 | effectVignette.uniforms[ "darkness" ].value = 1.6; 175 | 176 | var effectHBlur = new THREE.ShaderPass( THREE.ShaderExtras[ "horizontalBlur" ] ); 177 | var effectVBlur = new THREE.ShaderPass( THREE.ShaderExtras[ "verticalBlur" ] ); 178 | effectHBlur.uniforms[ 'h' ].value = 2 / ( window.innerWidth/2 ); 179 | effectVBlur.uniforms[ 'v' ].value = 2 / ( window.innerHeight/2 ); 180 | 181 | var effectDotScreen = new THREE.DotScreenPass( new THREE.Vector2( 0, 0 ), 0.1, 0.8 ); 182 | 183 | var rtWidth = window.innerWidth; 184 | var rtHeight = window.innerHeight; 185 | rtParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: true }; 186 | 187 | var renderModel = new THREE.RenderPass( scene, camera ); 188 | composer1 = new THREE.EffectComposer( renderer, new THREE.WebGLRenderTarget( rtWidth, rtHeight, rtParameters ) ); 189 | composer1.addPass( renderModel ); 190 | composer1.addPass( effectVignette ); 191 | composer1.addPass( effectDotScreen ); 192 | effectDotScreen.renderToScreen = true; 193 | // effectVignette.renderToScreen = true; 194 | // renderModel.renderToScreen = true; 195 | 196 | container.appendChild( renderer.domElement ); 197 | 198 | // stats = new Stats(); 199 | // stats.domElement.style.position = 'absolute'; 200 | // stats.domElement.style.top = '0px'; 201 | // container.appendChild( stats.domElement ); 202 | } 203 | 204 | function animate() { 205 | requestAnimationFrame( animate ); 206 | render(); 207 | // stats.update(); 208 | } 209 | 210 | function updateBlockZ() { 211 | // renderer.render( delta ); 212 | 213 | var pixels = depthImage.data; 214 | for ( var i = 0; i < gridlength; i ++ ) { 215 | 216 | var row = Math.floor( i / gridwidth ); 217 | var col = Math.floor( i % gridwidth ); 218 | 219 | var object = objects[i]; 220 | 221 | var px = Math.round(col * depthImage.width / gridwidth); 222 | var py = Math.round(row * depthImage.height / gridheight); 223 | 224 | var pixel = pixels[(py*depthImage.width+px)*4]; 225 | if( pixel == 0 ) 226 | pixel = 255; 227 | 228 | object.position.z = -((pixel-128)*5) - 400; 229 | 230 | // object.rotation.x += delta; 231 | // object.rotation.y += delta*(i+50)/100; 232 | // object.rotation.z += delta*i/100; 233 | } 234 | } 235 | 236 | function render() { 237 | renderer.clear(); 238 | composer1.render( delta ); 239 | 240 | 241 | } 242 | 243 | 244 | 245 | 246 | setTimeout(function(){ 247 | getDepthFrame(); 248 | init(); 249 | animate(); 250 | }, 500); 251 | 252 | 253 | }); 254 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /src/node_freenect.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Node.js addon for libfreenect. 3 | */ 4 | 5 | //------------------------------------------------------------------------- 6 | // Includes 7 | //------------------------------------------------------------------------- 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | //------------------------------------------------------------------------- 20 | // Defines 21 | //------------------------------------------------------------------------- 22 | // Taken from node-usb 23 | #define V8STR(str) v8::String::New(str) 24 | #define THROW_BAD_ARGS(FAIL_MSG) return v8::ThrowException(v8::Exception::TypeError(V8STR(FAIL_MSG))); 25 | #define THROW_ERROR(FAIL_MSG) return v8::ThrowException(v8::Exception::Error(V8STR(FAIL_MSG)))); 26 | #define THROW_NOT_YET return v8::ThrowException(v8::Exception::Error(v8::String::Concat(v8::String::New(__FUNCTION__), v8::String::New("not yet supported")))); 27 | 28 | #define MAX_TILT_DEGS (31.0) 29 | #define MIN_TILT_DEGS (-31.0) 30 | #define INVALID_TILT_DEGS (-99.0) 31 | 32 | //------------------------------------------------------------------------- 33 | // libfreenect wrapper for Node.js 34 | //------------------------------------------------------------------------- 35 | class Freenect : node::ObjectWrap 36 | { 37 | public: 38 | 39 | Freenect() 40 | : deviceIndex(0), videoFormat(FREENECT_VIDEO_RGB), depthFormat(FREENECT_DEPTH_11BIT) 41 | { 42 | videoBuffer = malloc(freenect_find_video_mode(FREENECT_RESOLUTION_LOW, FREENECT_VIDEO_RGB).bytes); 43 | depthBuffer = malloc(freenect_find_depth_mode(FREENECT_RESOLUTION_LOW, FREENECT_DEPTH_11BIT).bytes); 44 | tiltState = new freenect_raw_tilt_state(); 45 | tiltAngle = GetTiltAngle(); 46 | } 47 | 48 | virtual ~Freenect() 49 | { 50 | free(videoBuffer); 51 | free(depthBuffer); 52 | freenect_sync_stop(); 53 | } 54 | 55 | /** 56 | * Set LED option. 57 | * 58 | * @param option LED option to set. 59 | * @return True if set tilt angle success. 60 | */ 61 | bool SetLed(freenect_led_options option) 62 | { 63 | int ret = freenect_sync_set_led(option, deviceIndex); 64 | if (ret < 0) { 65 | printf("Could set LED %d\n", option); 66 | return false; 67 | } 68 | ledOption = option; 69 | return true; 70 | } 71 | 72 | /** 73 | * Set tilt angle. 74 | * 75 | * @param angle Tilt angle toset. Range [-30.0..30.0] 76 | * @return True if set tilt angle success. 77 | */ 78 | bool SetTiltAngle(double angle) 79 | { 80 | double deg = angle; 81 | if (deg <= MIN_TILT_DEGS) { 82 | deg = MIN_TILT_DEGS; 83 | } 84 | if (deg >= MAX_TILT_DEGS) { 85 | deg = MAX_TILT_DEGS; 86 | } 87 | 88 | int ret = freenect_sync_set_tilt_degs(deg, deviceIndex); 89 | if (ret < 0) { 90 | printf("Could set tilt degs %f\n", deg); 91 | return false; 92 | } 93 | tiltAngle = deg; 94 | return true; 95 | } 96 | 97 | /** 98 | * Get video or IR buffer from kinect. 99 | * 100 | * @return Video buffer or NULL on error. 101 | */ 102 | void* GetVideo() 103 | { 104 | uint32_t timestamp; 105 | int ret = freenect_sync_get_video(&videoBuffer, ×tamp, deviceIndex, videoFormat); 106 | if (ret != 0) { 107 | printf("Could not get video\n"); 108 | return NULL; 109 | } 110 | return videoBuffer; 111 | } 112 | 113 | /** 114 | * Get depth buffer from kinect. 115 | * 116 | * @return Depth buffer or NULL on error. 117 | */ 118 | void* GetDepth() 119 | { 120 | uint32_t timestamp; 121 | int ret = freenect_sync_get_depth(&depthBuffer, ×tamp, deviceIndex, depthFormat); 122 | if (ret != 0) { 123 | printf("Could not get depth\n"); 124 | return NULL; 125 | } 126 | return depthBuffer; 127 | } 128 | 129 | /** 130 | * Get tilt angle of kinect. 131 | * 132 | * @return Depth buffer data 133 | */ 134 | double GetTiltAngle() 135 | { 136 | int ret = freenect_sync_get_tilt_state(&tiltState, deviceIndex); 137 | if (ret != 0) { 138 | printf("Could not get tilt angle\n"); 139 | return INVALID_TILT_DEGS; 140 | } 141 | double angle = freenect_get_tilt_degs(tiltState); 142 | return angle; 143 | } 144 | 145 | /** 146 | * Stop conecting to kinect device. 147 | */ 148 | void Stop() 149 | { 150 | freenect_sync_stop(); 151 | } 152 | 153 | //------------------------------------------------------------------------ 154 | 155 | //------------------------------------------------------------------------ 156 | // Export functions. 157 | //------------------------------------------------------------------------ 158 | 159 | /** 160 | * Constructor for Node.js. 161 | * 162 | * @param args Constructor arguments passed from Node.js 163 | * @return Freenect component for Node.js 164 | */ 165 | static v8::Handle New(const v8::Arguments& args) 166 | { 167 | v8::HandleScope scope; 168 | 169 | Freenect* freenect = new Freenect(); 170 | freenect->Wrap(args.This()); 171 | freenect->Ref(); 172 | return args.This(); 173 | } 174 | 175 | /** 176 | * Set LED options. 177 | * 178 | * @param args Arguments list. 179 | * @return {Boolean} true if args is valid options. 180 | */ 181 | static v8::Handle SetLed(const v8::Arguments& args) 182 | { 183 | v8::HandleScope scope; 184 | 185 | if (args.Length() != 1) { 186 | THROW_BAD_ARGS("SetLed must have 1 argument.") 187 | } 188 | 189 | v8::Local ledOption = args[0]; 190 | if (!ledOption->IsInt32()) { 191 | THROW_BAD_ARGS("SetLed must have 1 int argument.") 192 | } 193 | 194 | int n = ledOption->Int32Value(); 195 | if (n < LED_OFF) { 196 | n = LED_OFF; 197 | } 198 | if (n > LED_BLINK_RED_YELLOW) { 199 | n = LED_BLINK_RED_YELLOW; 200 | } 201 | 202 | Freenect* freenect = getThis(args); 203 | bool ret = freenect->SetLed(static_cast(n)); 204 | return v8::Boolean::New(ret); 205 | } 206 | 207 | /** 208 | * Set tilt angle of kinect. 209 | * 210 | * @param args Arguments list. 211 | * @return {Boolean} true if args is valid options. 212 | */ 213 | static v8::Handle SetTiltAngle(const v8::Arguments& args) 214 | { 215 | v8::HandleScope scope; 216 | 217 | if (args.Length() != 1) { 218 | THROW_BAD_ARGS("SetTiltAngle must have 1 argument.") 219 | } 220 | 221 | v8::Local angle = args[0]; 222 | if (!angle->IsNumber()) { 223 | THROW_BAD_ARGS("SetTiltAngle must have 1 number argument.") 224 | } 225 | 226 | double a = angle->NumberValue(); 227 | 228 | Freenect* freenect = getThis(args); 229 | bool ret = freenect->SetTiltAngle(a); 230 | return v8::Boolean::New(ret); 231 | } 232 | 233 | /** 234 | * Get RBG image of kinect. 235 | * 236 | * @param args Arguments list. 237 | * @return {Array.} RGB pixel data 238 | */ 239 | static v8::Handle GetVideo(const v8::Arguments& args) 240 | { 241 | v8::HandleScope scope; 242 | 243 | Freenect* freenect = getThis(args); 244 | unsigned char* buf = static_cast(freenect->GetVideo()); 245 | int length = freenect_find_video_mode(FREENECT_RESOLUTION_LOW, FREENECT_VIDEO_RGB).bytes; 246 | v8::Local array = v8::Array::New(length); 247 | /* 248 | for (int i = 0; i < length; i+=16) { 249 | array->Set(i , v8::Uint32::New(buf[i ])); 250 | array->Set(i+1 , v8::Uint32::New(buf[i+ 1])); 251 | array->Set(i+2 , v8::Uint32::New(buf[i+ 2])); 252 | array->Set(i+3 , v8::Uint32::New(buf[i+ 3])); 253 | array->Set(i+4 , v8::Uint32::New(buf[i+ 4])); 254 | array->Set(i+5 , v8::Uint32::New(buf[i+ 5])); 255 | array->Set(i+6 , v8::Uint32::New(buf[i+ 6])); 256 | array->Set(i+7 , v8::Uint32::New(buf[i+ 7])); 257 | array->Set(i+8 , v8::Uint32::New(buf[i+ 8])); 258 | array->Set(i+9 , v8::Uint32::New(buf[i+ 9])); 259 | array->Set(i+10, v8::Uint32::New(buf[i+10])); 260 | array->Set(i+11, v8::Uint32::New(buf[i+11])); 261 | array->Set(i+12, v8::Uint32::New(buf[i+12])); 262 | array->Set(i+13, v8::Uint32::New(buf[i+13])); 263 | array->Set(i+14, v8::Uint32::New(buf[i+14])); 264 | array->Set(i+15, v8::Uint32::New(buf[i+15])); 265 | } 266 | */ 267 | return array; 268 | } 269 | 270 | /** 271 | * Get video buffer of kinect. 272 | * 273 | * @param args Arguments list. 274 | * @return {Buffer} Video buffer data (RGB) 275 | */ 276 | static v8::Handle GetVideoBuffer(const v8::Arguments& args) 277 | { 278 | v8::HandleScope scope; 279 | 280 | Freenect* freenect = getThis(args); 281 | char* buf = static_cast(freenect->GetVideo()); 282 | node::Buffer* retbuf = node::Buffer::New(buf, freenect_find_video_mode(FREENECT_RESOLUTION_LOW, FREENECT_VIDEO_RGB).bytes); 283 | return retbuf->handle_; 284 | } 285 | 286 | /** 287 | * Get depth buffer of kinect. 288 | * 289 | * @param args Arguments list. 290 | * @return {Array.} Depth buffer data 291 | */ 292 | static v8::Handle GetDepth(const v8::Arguments& args) 293 | { 294 | v8::HandleScope scope; 295 | 296 | Freenect* freenect = getThis(args); 297 | uint16_t* buf = static_cast(freenect->GetDepth()); 298 | int length = 640*480; 299 | v8::Local array = v8::Array::New(length); 300 | for (int i = 0; i < length; i+=16) { 301 | array->Set(i , v8::Uint32::New(buf[i ])); 302 | array->Set(i+1 , v8::Uint32::New(buf[i+ 1])); 303 | array->Set(i+2 , v8::Uint32::New(buf[i+ 2])); 304 | array->Set(i+3 , v8::Uint32::New(buf[i+ 3])); 305 | array->Set(i+4 , v8::Uint32::New(buf[i+ 4])); 306 | array->Set(i+5 , v8::Uint32::New(buf[i+ 5])); 307 | array->Set(i+6 , v8::Uint32::New(buf[i+ 6])); 308 | array->Set(i+7 , v8::Uint32::New(buf[i+ 7])); 309 | array->Set(i+8 , v8::Uint32::New(buf[i+ 8])); 310 | array->Set(i+9 , v8::Uint32::New(buf[i+ 9])); 311 | array->Set(i+10, v8::Uint32::New(buf[i+10])); 312 | array->Set(i+11, v8::Uint32::New(buf[i+11])); 313 | array->Set(i+12, v8::Uint32::New(buf[i+12])); 314 | array->Set(i+13, v8::Uint32::New(buf[i+13])); 315 | array->Set(i+14, v8::Uint32::New(buf[i+14])); 316 | array->Set(i+15, v8::Uint32::New(buf[i+15])); 317 | } 318 | return array; 319 | } 320 | 321 | /** 322 | * Get depth buffer of kinect. 323 | * 324 | * @param args Arguments list. 325 | * @return {Buffer} Depth buffer data 326 | */ 327 | static v8::Handle GetDepthBuffer(const v8::Arguments& args) 328 | { 329 | printf("entering getdepth\n"); 330 | v8::HandleScope scope; 331 | Freenect* freenect = getThis(args); 332 | uint16_t* buf = static_cast(freenect->GetDepth()); 333 | freenect_frame_mode mode = freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT); 334 | int length = mode.width * mode.height; 335 | printf("valid:%d, width:%d, height:%d, length:%d\n", mode.is_valid, mode.width, mode.height, length); 336 | if(!mode.is_valid) 337 | return v8::Boolean::New(false); 338 | char *buf2 = (char *)malloc(length);//[640*480] = { 0,1,2,3,4,5 }; 339 | printf("ptr buf=0x%08X, buf2=0x%08X\n", (unsigned long)buf, (unsigned long)buf2); 340 | for (int i = 0; i < length; i++) { 341 | buf2[i] = rand()&255;//buf[i] >> 2; 342 | } 343 | node::Buffer* retbuf = node::Buffer::New(buf2, length); 344 | free(buf2); 345 | printf("leaving getdepth\n"); 346 | return retbuf->handle_; 347 | } 348 | 349 | /** 350 | * Get scaled depth buffer of kinect. 351 | * 352 | * @param args Arguments list. 353 | * @return {Buffer} Depth buffer data 354 | */ 355 | static v8::Handle GetScaledDepthBuffer(const v8::Arguments& args) 356 | { 357 | 358 | if (args.Length() != 2) { 359 | THROW_BAD_ARGS("GetScaledDepthBuffer must have 2 arguments.") 360 | } 361 | 362 | v8::Local w_param = args[0]; 363 | v8::Local h_param = args[1]; 364 | if (!w_param->IsNumber() && !h_param->IsNumber()) { 365 | THROW_BAD_ARGS("SetTiltAngle must have 2 number argument.") 366 | } 367 | 368 | int outputwidth = (int)w_param->NumberValue(); 369 | int outputheight = (int)h_param->NumberValue(); 370 | 371 | v8::HandleScope scope; 372 | Freenect* freenect = getThis(args); 373 | uint16_t* buf = static_cast(freenect->GetDepth()); 374 | freenect_frame_mode mode = freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT); 375 | int length = mode.width * mode.height; 376 | int outputlength = outputwidth * outputheight; 377 | printf("valid:%d, width:%d (%d), height:%d (%d), length:%d\n", mode.is_valid, mode.width, outputwidth, mode.height, outputheight, length); 378 | char *buf2 = (char *)malloc(length);//[640*480] = { 0,1,2,3,4,5 }; 379 | char *buf3 = (char *)malloc(outputlength);//[640*480] = { 0,1,2,3,4,5 }; 380 | printf("ptr buf=0x%08X, buf2=0x%08X\n", (unsigned long)buf, (unsigned long)buf2); 381 | 382 | // scale to bytes 383 | for (int i = 0; i < length; i++) { 384 | buf2[i] = buf[i] >> 2; 385 | } 386 | 387 | // ugly downscaler 388 | 389 | int oo = 0; 390 | int istride = mode.width; 391 | for(int j=0; jhandle_; 405 | } 406 | 407 | /** 408 | * Get tilt angle of kinect. 409 | * 410 | * @param args Arguments list. 411 | * @return {Number} Depth buffer data 412 | */ 413 | static v8::Handle GetTiltAngle(const v8::Arguments& args) 414 | { 415 | v8::HandleScope scope; 416 | 417 | Freenect* freenect = getThis(args); 418 | double angle = freenect->GetTiltAngle(); 419 | return v8::Number::New(angle); 420 | } 421 | 422 | /** 423 | * Stop connecting to kinect. 424 | * 425 | * @param args Arguments list. 426 | * @return {undefined} 427 | */ 428 | static v8::Handle Stop(const v8::Arguments& args) 429 | { 430 | v8::HandleScope scope; 431 | 432 | Freenect* freenect = getThis(args); 433 | freenect->Stop(); 434 | return v8::Undefined(); 435 | } 436 | 437 | private: 438 | int deviceIndex; 439 | double tiltAngle; 440 | 441 | freenect_led_options ledOption; 442 | freenect_raw_tilt_state* tiltState; 443 | freenect_video_format videoFormat; 444 | freenect_depth_format depthFormat; 445 | 446 | void* videoBuffer; 447 | void* depthBuffer; 448 | 449 | /** 450 | * Get this pointer from v8::Arguments. 451 | */ 452 | static Freenect* getThis(const v8::Arguments& args) 453 | { 454 | Freenect* freenect = ObjectWrap::Unwrap(args.This()); 455 | return freenect; 456 | } 457 | 458 | }; 459 | 460 | //------------------------------------------------------------------------- 461 | // Node.js addon interfaces 462 | //------------------------------------------------------------------------- 463 | 464 | extern "C" void init(v8::Handle target) 465 | { 466 | v8::HandleScope scope; 467 | 468 | v8::Local t = v8::FunctionTemplate::New(Freenect::New); 469 | t->InstanceTemplate()->SetInternalFieldCount(1); 470 | NODE_SET_PROTOTYPE_METHOD(t, "setLed", Freenect::SetLed); 471 | NODE_SET_PROTOTYPE_METHOD(t, "setTiltAngle", Freenect::SetTiltAngle); 472 | NODE_SET_PROTOTYPE_METHOD(t, "getTiltAngle", Freenect::GetTiltAngle); 473 | NODE_SET_PROTOTYPE_METHOD(t, "getVideo", Freenect::GetVideo); 474 | NODE_SET_PROTOTYPE_METHOD(t, "getVideoBuffer", Freenect::GetVideoBuffer); 475 | NODE_SET_PROTOTYPE_METHOD(t, "getDepth", Freenect::GetDepth); 476 | NODE_SET_PROTOTYPE_METHOD(t, "getDepthBuffer", Freenect::GetDepthBuffer); 477 | NODE_SET_PROTOTYPE_METHOD(t, "getScaledDepthBuffer", Freenect::GetScaledDepthBuffer); 478 | NODE_SET_PROTOTYPE_METHOD(t, "stop", Freenect::Stop); 479 | target->Set(v8::String::New("Kinect"), t->GetFunction()); 480 | } 481 | 482 | 483 | 484 | -------------------------------------------------------------------------------- /example/simpleviewer/public/javascripts/socket.io.js: -------------------------------------------------------------------------------- 1 | /* Socket.IO.min 0.6.2 @author Guillermo Rauch , @license The MIT license., @copyright Copyright (c) 2010 LearnBoost */ 2 | var io=this.io={version:"0.6.2",setPath:function(a){window.console&&console.error&&console.error("io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf"),this.path=/\/$/.test(a)?a:a+"/",WEB_SOCKET_SWF_LOCATION=a+"lib/vendor/web-socket-js/WebSocketMain.swf"}};"jQuery"in this&&(jQuery.io=this.io),typeof window!="undefined"&&typeof WEB_SOCKET_SWF_LOCATION=="undefined"&&(WEB_SOCKET_SWF_LOCATION="/socket.io/lib/vendor/web-socket-js/WebSocketMain.swf"),function(){var a=this.io,b=!1;a.util={ios:!1,load:function(a){if(/loaded|complete/.test(document.readyState)||b)return a();"attachEvent"in window?window.attachEvent("onload",a):window.addEventListener("load",a,!1)},inherit:function(a,b){for(var c in b.prototype)a.prototype[c]=b.prototype[c]},indexOf:function(a,b,c){for(var d=a.length,e=c<0?Math.max(0,d+c):c||0;e"),this._doc.parentWindow.s=this,this._doc.close();var a=this._doc.createElement("div");this._doc.body.appendChild(a),this._iframe=this._doc.createElement("iframe"),a.appendChild(this._iframe),this._iframe.src=this._prepareUrl()+"/"+ +(new Date)},b.prototype._=function(a,b){this._onData(a);var c=b.getElementsByTagName("script")[0];c.parentNode.removeChild(c)},b.prototype._destroy=function(){this._iframe&&(this._iframe.src="about:blank",this._doc=null,CollectGarbage())},b.prototype.disconnect=function(){this._destroy();return a.Transport.XHR.prototype.disconnect.call(this)},b.check=function(){if("ActiveXObject"in window)try{var b=new ActiveXObject("htmlfile");return b&&a.Transport.XHR.check()}catch(c){}return!1},b.xdomainCheck=function(){return!1}}(),function(){var a=this.io,b=a.Transport["xhr-multipart"]=function(){a.Transport.XHR.apply(this,arguments)};a.util.inherit(b,a.Transport.XHR),b.prototype.type="xhr-multipart",b.prototype._get=function(){var a=this;this._xhr=this._request("","GET",!0),this._xhr.onreadystatechange=function(){a._xhr.readyState==4&&a._onData(a._xhr.responseText)},this._xhr.send(null)},b.check=function(){return"XMLHttpRequest"in window&&"prototype"in XMLHttpRequest&&"multipart"in XMLHttpRequest.prototype},b.xdomainCheck=function(){return!0}}(),function(){var a=this.io,b=new Function,c=a.Transport["xhr-polling"]=function(){a.Transport.XHR.apply(this,arguments)};a.util.inherit(c,a.Transport.XHR),c.prototype.type="xhr-polling",c.prototype.connect=function(){if(a.util.ios||a.util.android){var b=this;a.util.load(function(){setTimeout(function(){a.Transport.XHR.prototype.connect.call(b)},10)})}else a.Transport.XHR.prototype.connect.call(this)},c.prototype._get=function(){var a=this;this._xhr=this._request(+(new Date),"GET"),this._xhr.onreadystatechange=function(){var c;if(a._xhr.readyState==4){a._xhr.onreadystatechange=b;try{c=a._xhr.status}catch(d){}c==200?(a._onData(a._xhr.responseText),a._get()):a._onDisconnect()}},this._xhr.send(null)},c.check=function(){return a.Transport.XHR.check()},c.xdomainCheck=function(){return a.Transport.XHR.xdomainCheck()}}(),function(){var a=this.io;a.JSONP=[],JSONPPolling=a.Transport["jsonp-polling"]=function(){a.Transport.XHR.apply(this,arguments),this._insertAt=document.getElementsByTagName("script")[0],this._index=a.JSONP.length,a.JSONP.push(this)},a.util.inherit(JSONPPolling,a.Transport["xhr-polling"]),JSONPPolling.prototype.type="jsonp-polling",JSONPPolling.prototype._send=function(a){function h(){b._iframe&&b._form.removeChild(b._iframe);try{f=document.createElement('