Hey Arturo & Kyle my last post (in between yours) got swallowed by the spam bot apparently.
I’ll try again with less words
…in the end it’s the code and the feedback about what pattern/structure people find most useful is what makes me happiest!
On that note:
Last night I took Arturo’s approach and re-instated initialising generators from code (as opposed to init’ing from XML) and started testing for multiple Kinect compatibility - something I believe is very high on everyones list of functionality. I had to do a bunch of tests to figure out how this should work -> at first I thought there could be a separate xn::Context for each device, but it turns out this is not the case. However, with a single xn:Context I am getting really good performance (even on my Macbook Pro) which is exciting.
This poses an immediate problem of how to structure access to a single threaded xn::Context whilst maintaining a simple API for dealing with several Kinects simultaneously.
By far the easiest is to leave an xn::Context in a threaded openNI class, and then use a vector/array to store instances of an openNIDevice (or something similiar) which would look very much like what Arturo has got in openNI.h/.cpp.
This would lead to code like:
openNI.setup(); //or openNI.setupFromXML(someFile.xml); would only need a single setup for all devices
openNI.getDevice(0).addDepth(); // or could use operator overloading of  so that we can use
openNI.getDevice(0).addImage(); // openNI.addDepth() - but then we lose code completion
openNI.addDepth(0); // where the int is the device number???
openNI.addImage(0); // this is how I did things last night for speed of development
openNI.addDepth(1); // it has the advantage of being able to set a default value of 0 in all the normally
openNI.addImage(1); // accessed functions so that for single instances everything is invisible to the user, but is maybe a bit messy?
openNI.update(); //we'd only need one update, not per device as we could track instances easily
openNI.drawDebug(); // could draw all depth/image/ir/nodes etc
openNI.getDevice(0).drawDepth(0,0,320,240); // class method to determine device
openNI.drawDepth(0,0,320,240, 0 <- deviceID); // pass variable to determine device
openNI.drawRGB(0,0,320,240, 1 <- deviceID);
openNI.drawDepth(0,0,320,240); // operator overload to determine device
However this leads to some (possibly) annoying nomenclature and departs from the ofVideoPlayer/VideoGrabber/SoundPlayer/etc model where we can just declare instances of the device/player class and use listDevices, setDeviceID and initKinect to allocate a device to each instance (as much as I’m not a fan of these method names they are common across a number of classes).
I’m assuming some people might prefer code that looks like:
ofxOpenNI openNI; // or ofxOpenNI openNIA; ofxOpenNI openNIB; or ofxOpenNI * openNI; new ofxOpenNI; etc
opeNI.listDevices(); (or openNI.getDevices() - which I prefer but is not standard
openNI.initKinect(...some arguments...width, height, fps, threaded, a bit mask of nodes to add????);
openNI.setup(...args...); again I prefer this but it's not what we have in other classes, which to use?
openNI.update(); // we'd need to call for each device with this method, even if the xn::Context is 'hidden' and threading in the background somewhere
Feedback about this would most super helpful right now
a vector is exactly the same as an array it depends on how you use it. coincidentally i just wrote an article about that in my blog: [http://arturocastro.net/blog/2011/10/28/stl::vector/
That article is really great -> I’ve been wanting to talk about vectors vs arrays for some time now. I’ve done some testing to compare based on your article. Results-and-code-are-in-a-new-thread…the gist is that I found everything you talk about in that article to be true until I get to allocations over a certain amount of bytes, then I get mixed results, with push_back starting to work faster than  index access on vectors, and arrays out and out faster on multidimensional data (eg., like unsigned char[1920*1080*4] to store a bunch of pixel masks)…
The back/front buffers is in effect for avoiding tearing, at that resolution it shouldn’t happen but better to be sure mostly when this images are going to be used for analysis more than just drawing them
I’m not sure in this case it’s necessary. The command xn::Context::WaitAnyUpdateAll (or variant thereof) ensures that all data from the kinect finishes processing before the MetaData objects are (re-)populated with data. Therefore if we lock()/unlock() during the process of generating textures (rather than when swap’ing the pointers) we should have no risk of tearing…and essentially this is a double buffer already. Doing it again seems like it’s triple buffering!? Is there an efficiency issue for locking during MetaData retrieval?
My understanding (and I could be wrong here) is that if the lock/unlock is only around the swap, but the generation of image/depth pixels happens (without locks) as you have it, it’s possible for tearing to occur because the thread manages to fire twice (if that is even possible?). But then swap’ing the back buffer is just going to make a copy of the ‘torn’ pixels. Please let me know if I have that upside down.
My reason for asking on about it is that I am using this to do a lot of registered projection (where the image is re-projected back onto the moving subject) and any unnecessary double (or in this case triple?) buffering is going to add latency.