Laser Sensing Display for UI interfaces in the real world

Dependencies:   mbed

Fork of skinGames_forktest by Alvaro Cassinelli

Scene.cpp

Committer:
mbedalvaro
Date:
2014-04-17
Revision:
47:199042980678
Parent:
43:1dd4cfc30788

File content as of revision 47:199042980678:

#include "Scene.h"
//#include "hardwareIO.h" //(for tests using serial port only)

Scene scene; // pre-instantiated GLOBAL (cross file object, declared extern in the Scene.h header)

//extern LaserRenderer lsr; // Use of the global object lsr (LaserRenderer type). Object is pre-instantiated in LaserRenderer.cpp
 
 using namespace std;

//======================================= BASE OBJECT CLASS =======================================
//BaseObject::BaseObject() {}

BaseObject::~BaseObject() {
 // in principle, we don't need to do anything: 
 // the vertexArray is a vector that does NOT contain pointers; also myDisplaySensingBuffer is destroyed by calling its destructor.
}


void BaseObject::addVertex(V3& _v3, Mat44& _RT) { // passing the current modelview (lsr.RT) as a parameter seems cleaner (more encapsulated class) than using the global lsr object...
    vertexArray.push_back(_RT*_v3); 
}

void BaseObject::transform(Mat44& _RT) { // this transform all the vertices of the object by _RT
    for (unsigned short i=0; i<vertexArray.size(); i++) vertexArray[i]=_RT*vertexArray[i];
}

void BaseObject::clear() { // this deletes all the vertices (and their projections) in the object:
    vertexArray.clear();
    displaySensingBuffer.lsdTrajectory.clear();
}

/*  THIS PRODUCE A CIRCULAR REFERENCE!
void BaseObject::render(LaserRenderer* ptr_lsr) {
  // Use the lsr methods: again, this would be kind of convoluted if these objects belongs to a scene that belongs to lsr...
  ptr_lsr->renderObject(this);
*/

 //Or do it "directly" (but again, we need to use data from the lsr state machine): 
/*
// First, clear the current lsdTrajectory:
  Object.myDisplaySensingBuffer.lsdTrajectory.clear();
 if (lsr.renderingMode==PROJECTION)
    for (int i=0; i<vertexArray.size(); i++) {
    LaserPoint newLp=lsr.renderPointProj(Object.vertexArray[i]); // or use a render method for a LaserPoint or an extended V3 class (or directly)
    // Set per-vertex color too? No, for the time being one color per object... 
    // newLp.myColor=color;
    Object.myDisplaySensingBuffer.lsdTrajectory.push_back(newLp);
 }
 else
    for (int i=0; i<Object.vertexArray.size(); i++) {
    LaserPoint newLp=lsr.renderPointRaw(Object.vertexArray[i]);
    // Set per-vertex color too? No, for the time being one color per object... 
    // newLp.myColor=color;
    Object.myDisplaySensingBuffer.lsdTrajectory.push_back(newLp);
    }
}
}
*/

Box3d BaseObject::getEnclosingBox() {
    // This will give the 3d enclosing box for the object, in LOCAL coordinates. 
    // (for the time being, let's compute every time we query about it. In the future we can optimize by computing only when the object changed)
    if (vertexArray.size()==0) {
    enclosingBox.minX=enclosingBox.maxX=enclosingBox.minY=enclosingBox.maxY=enclosingBox.minZ=enclosingBox.maxZ=0;
    } 
    else 
    { 
       enclosingBox.minX=enclosingBox.maxX=vertexArray[0].x;
       enclosingBox.minY=enclosingBox.maxY=vertexArray[0].y;
       enclosingBox.minZ=enclosingBox.maxZ=vertexArray[0].z;
        for (unsigned short i=1; i<vertexArray.size(); i++) {
            if (vertexArray[i].x>enclosingBox.maxX) enclosingBox.maxX=vertexArray[i].x;
            else if (vertexArray[i].x<enclosingBox.minX) enclosingBox.minX=vertexArray[i].x;
            if (vertexArray[i].y>enclosingBox.maxY) enclosingBox.maxY=vertexArray[i].y;
            else if (vertexArray[i].y<enclosingBox.minY) enclosingBox.minY=vertexArray[i].y;
        }
      }
    return (enclosingBox);
}

 // Sensing methods (query and process sensed data): 
 // That this is separated from displaying routine make sense: we can query at ANY time for new data,
 // and this is uncorrelated with the display buffer continuous to work, displaying and sensing things.
 // ALSO, it is separated from the LaserRenderer: this routine does not uses any "state machine" data.  
 bool BaseObject::sense() {return(this->displaySensingBuffer.processSensedData());}

 // Max and Min intensity RATIOS (normalized between 0 and 255):
unsigned char BaseObject::maxIntensity(void) {displaySensingBuffer.processSensedData(); return displaySensingBuffer.maxI;}
unsigned char BaseObject::minIntensity(void) {displaySensingBuffer.processSensedData(); return displaySensingBuffer.minI;}
    

//======================================= THE SCENE CLASS =======================================

//Scene::Scene() : numTouchedObjects(0) {}

Scene::~Scene() {
    this->clear(); // necessary because Scene object variable objectArray is an vector of POINTERS and we need to free memory for the pointed objects. 
}

void Scene::clear() {
 //NOTE: objectArray stores POINTERS to objects; we need therefore to delete first the object itself:
  for (int i=0; i<this->totalObjects(); i++) {
    // pc.printf("deleting object: %d\n", i);
     delete objectArray[i]; // this call the destructor for BaseObject
   }
    objectArray.clear(); // clear the vector of pointers
    ptr_currentObject=NULL;
 }
 
void Scene::addObject(BaseObject* ptr_newObject) {
    objectArray.push_back(ptr_newObject); // note: the object pointed by ptr_newObject has been instantiated OUTSIDE this method. 
    //ptr_currentObject=ptr_newObject;
}

void Scene::addCurrentObject() { // this adds the "current" object (pointed by ptr_currentObject)
    objectArray.push_back(ptr_currentObject);
  // Note: the current object pointerd by ptr_currentObject can be BaseObject... or any child class. This is not a problem as long as the methods applied to the 
  // scene vector array don't use child methods (then we can do a dynamic cast before including in the array: pb = dynamic_cast<CBase*>(&d); ). IF we want
  // the scene class to be able to use child methods, then we need to make BaseObject polymorphic, by declaring all usable methods VIRTUAL.
 
}

void Scene::transform(Mat44& _RT) { // this transform all the objects of the scene by _RT
    for (int i=0; i<totalObjects(); i++) objectArray[i]->transform(_RT);
}

// ATTENTION: deleting objects imply stoping the displaying engine, and updating. This is mandatory, not in the case of ADDING objects...
void Scene::deleteObject(int _id) {
    // We could use an STL map, but here I will do the matching manually:
    for (int i=0; i<totalObjects(); i++) 
        if ( (objectArray[i]->ID()) == _id) objectArray.erase(objectArray.begin()+i); // note: I don't stop the for-loop. I delete ALL objects with this ID 
    // Not sure I will use the "current pointer", but if I do, then we need to decide what it becomes here... let's point to the last element in the vector: 
    if (!objectArray.empty()) ptr_currentObject=objectArray.back(); else ptr_currentObject=NULL;
}

// number of objects in the scene:
int Scene::totalObjects() {return(objectArray.size());}

// total number of points in the scene:
int Scene::totalPoints() {
int ttlpoints=0;
for (unsigned short i=0; i<objectArray.size(); i++) ttlpoints+=objectArray[i]->size();
return(ttlpoints);
}
    
/*
void Scene::render(LaserRenderer* ptr_lsr) {
    ptr_lsr->renderScene(this);
    // Or, if one want to use the object render method (that also calls lsr methods anyway, so it is heavier):
    //  for (int i=0; i<Scene.size(); i++) renderObject(ptr_scene->objectArray[i]);
}
*/

 int Scene::sense() {
 numTouchedObjects=0;
 for (int i=0; i<totalObjects(); i++) 
    if (objectArray[i]->displaySensingBuffer.processSensedData()) numTouchedObjects++;
 //touchedScene=(numTouchedObjects>0);
 return(numTouchedObjects); 
}