Laser Sensing Display for UI interfaces in the real world

Dependencies:   mbed

Fork of skinGames_forktest by Alvaro Cassinelli

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002 
00003 - NOTE: I could instantiate at least 960 points when NOT USING THE ETHERNET LIBRARY! (as 30 objects containing each 32 points). 
00004   ... but then again I could not make only 36 1-point object on a grid? what's going on? an object takes MUCH MORE MEMORY than just
00005   the trajectory and 3d vector array... but where?
00006   Anyway, using the ETHERNET LIBRARY uses more than 20kB, and then I cannot instantiate more than a few letters... 
00007 */
00008 
00009 //#define WITH_OSC // this consumes about 20kb or RAM!!!
00010 
00011 #include "mbed.h"
00012 #include "WrapperFunctions.h"
00013 
00014 #ifdef WITH_OSC
00015 #include "mbedOSC.h"
00016 #endif
00017 
00018 // The following is because I still did not "wrap" ALL the LaserRenderer methods (so we have to use the object lsr directly, for instance to set a matrix: lsr.setIdentityPose()...)
00019 #include "LaserRenderer.h"
00020 extern LaserRenderer lsr;
00021 
00022 // mbed IP address (server):
00023 #ifdef WITH_OSC
00024 #ifdef DHCP
00025 EthernetNetIf eth;
00026 #else
00027 EthernetNetIf eth(
00028     IpAddr(10,0,0,2), //IP Address of the mbed
00029     IpAddr(255,255,255,0), //Network Mask
00030     IpAddr(10,0,0,1), //Gateway
00031     IpAddr(10,0,0,1)  //DNS
00032 );
00033 #endif
00034 
00035 //uint8_t serverMac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
00036 uint8_t serverIp[]  = { 10, 0, 0, 2 };
00037 int  serverPort  = 10000;
00038 
00039 //uint8_t destIp[]  = {10, 0, 0, 3};
00040 uint8_t destIp[]  = {255, 255, 255, 255};  // broadcast, so we can use several computers for sound, etc
00041 int  destPort = 12000;
00042 
00043 char *topAddress="/mbed";
00044 char *subAddress[3]= { "/test1" , "/test2" , "/test3" };
00045 
00046 OSCMessage recMes;
00047 OSCMessage sendMes;
00048 
00049 OSCClass osc;
00050 //OSCClass osc(&recMes);  // instantiate OSC communication object, and set the receiver container from the OSC packets
00051 #endif
00052 
00053 // for tests:
00054 extern Scene scene;
00055 extern laserSensingDisplay lsd;
00056 
00057 // =======================================================
00058 
00059 // Timers:
00060 Timer t; // we can read in ms or us
00061 
00062 // Tickers:
00063 //Ticker timerForRendering; // now in the WrapperFunctions.cpp file
00064 //Ticker timerForSendingData; // better use a timer, so as not to interrupt the exact laser display ticker
00065 unsigned long lastTimeCreated;
00066 unsigned long lastTimeSensed;
00067 
00068 // ======================================================================================================================
00069 // DEFAULT CALIBRATION MATRICES (Extrinsics and Intrinsics).
00070 // -> would be better to load them from a system file!! (TO DO)
00071 // Note: last row is completed automatically in the loadExtrinsicMatrix and loadProjMatrix methods
00072 // Extrinsics of usb camera to projector (note: calibration was in cm, so the translation vector is in cm)
00073 float E1[12] = {9.8946330287356954e-01, -5.0979372852926171e-03, -1.4469410251272136e-01,  5.8356271792647112e+00,
00074                 -4.7536907255693065e-03,  9.9769720674821438e-01, -6.7658599389111715e-02, -6.0821695799283804e+00,
00075                 1.4470582120637832e-01,  6.7633532232509466e-02,  9.8716053943963022e-01, -8.2545447546057940e+00
00076                };
00077 
00078 // 9.9540692993883650e-01, -8.5578652572728450e-03, -9.5350966287597705e-02, 2.2256570914518332e+00,
00079 //                1.4872282274740087e-02,  9.9772789680840523e-01, 6.5710418886328711e-02, -6.9310510316834923e+00,
00080 //                 9.4571978141945845e-02, -6.6826692814433777e-02, 9.9327253766416224e-01,  1.0699927478132011e+01
00081 //};
00082 
00083 
00084 // INTRINSICS of laser projector:
00085 float K1[6] = { 5.9957148864529627e+03, 0.0000000e+000, 2.8869455045867635e+03,
00086                 0.0000000e+000,         5.9647451141521778e+03, 2.9005238051336592e+03
00087               };
00088 
00089 // 7.0776317995422105e+03, 0., 2.4203185896583996e+03,
00090 //                0.,                     7.2889265345161484e+03, 1.7718110988625751e+03};
00091 
00092 // SCALE FACTOR for the SCAN:
00093 float scaleFactorProjector1 = 1.0; //scale factor for the projector image (the scan is, say, 600x600, but the resolution is 4096x4096)
00094 
00095 // ======================================================================================================================
00096 // LASER TERMINAL:
00097 // We assume that the "terminal" is operating on an a4 page. Units are in cm.
00098 V2 cursorPosition(0,0);
00099 
00100 void createTextScene();
00101 void addText(string, int, float, float);
00102 
00103 float angle;
00104 string textToDisplay = "O";
00105 float fontWidth = 2.5, fontHeight = 2.5; // if calibration is in cm, then this is in cm.
00106 
00107 // ==============================================================================================================
00108 // Some global functions and variables (find a better way to integrate this!)
00109 extern "C" void mbed_reset();
00110 
00111 void createSceneTest();
00112 void setOrthographicView();
00113 
00114 #ifdef WITH_OSC
00115 void processOSC(UDPSocketEvent e);
00116 #endif
00117 void interpretCommand();
00118 void processSerial();
00119 
00120 int touchedTimes = 0;
00121 enum sensingModes {NO_SENSING, SENSING_WHOLE_SCENE, SENSING_PER_OBJECT};
00122 sensingModes currentSensingMode=SENSING_PER_OBJECT;//NO_SENSING;
00123 
00124 // ================= AUXILIARY VARIABLES FOR INTERPRETING COMMAND FROM SERIAL OR OSC =========================
00125 // NOTE: the following arrays are GLOBAL (used in processOSC and processSerial, as well as in interpretCommand function):
00126 // max of two addresses (top and sub), of a max length of 24 characters:
00127 char address[2][24];
00128 //long auxdata[2]; // to store a max of two arguments (note: we will only use LONGs)
00129 int data[2]; // this is to have -1 as NO DATA, to detect errors.
00130 int numArgs;
00131 
00132 // An auxiliary buffer to store parameters data, or matrices, or points to load as vertices.
00133 // Note: for matrices (pose, projection), the maximum size we need is 12 floats, but as we will also receive vertices, let's give enough space (assuming
00134 // we can send 3d points, this means 3 floats per point; let's limit the number of points per object to 128 (a lot)
00135 float auxDataBuffer[128];
00136 int auxDataBuffer_index=0;
00137 
00138 // Commands:
00139 string command1, command2;
00140 
00141 // this is a hack for the time being:
00142 int objectID;
00143 int xx, yy; // initial position of object or displacement
00144 bool firstTimeDisplay=true;
00145 
00146 // ==============================================================================================================
00147 int main()
00148 {
00149 
00150     t.start();
00151     lastTimeCreated = t.read_ms();
00152     lastTimeSensed = t.read_ms();
00153     angle = 0;
00154 
00155     // Setup:
00156     // (1) Hardware init (laser powers, positions...):
00157     IO.init();
00158 
00159 #ifdef WITH_OSC
00160     // OSC initialization:
00161     // Set the Ethernet port:
00162     printf("Setting up...\r\n");
00163     EthernetErr ethErr = eth.setup();
00164     if (ethErr) {
00165         printf("Error %d in setup.\r\n", ethErr);
00166         return -1;
00167     }
00168     printf("Setup OK\r\n");
00169 
00170     //(1) Sending message:
00171     // Set IP and Port:
00172     sendMes.setIp( destIp );
00173     sendMes.setPort( destPort );
00174     // Set data:
00175     sendMes.setTopAddress(topAddress);
00176 
00177     //setting osc functionnality:
00178     //(2) Receiving:
00179     recMes.setIp( serverIp ); // not needed?
00180     osc.setReceiveMessage(&recMes); // this sets the receiver container for the OSC packets (we can avoid doing this if we use osc.getMessage() to get messages)
00181     osc.begin(serverPort, &processOSC); // binds the upd (osc) messages to an arbitrary listening port ("server" port), and callback function
00182     wait(1);
00183 #endif
00184 
00185     //===================================================================
00186 
00187     /*
00188         //EXAMPLE 1: simple geometry ======================================================
00189         // (1) Calibration matrices (Projection, and extrinsics - if needed):
00190         // Typically, the projection matrix is set from the PC side, or loaded by default (from file system).
00191         lsr.loadProjMatrix(K1, scaleFactorProjector1); // we could use a wrapper, but I won't for the time being.
00192 
00193         // (2) Create the scene in "local" coordinates:
00194         createSceneTest(); // Create a default scene (for tests)
00195 
00196          // (3) Set a default GLOBAL POSE and PROJECTION MATRIX (if we changed it) for rendering and start displaying:
00197          // - Using the current K (that correct for the center of the camera too!):
00198         //lsr.setIdentityPose();
00199         //lsr.translate(0, 0, 2000);
00200         // - or doing orthoprojection:
00201         lsr.setOrthoProjection();
00202         lsr.setIdentityPose();
00203         lsr.translate(CENTER_AD_MIRROR_X, CENTER_AD_MIRROR_Y, 0);
00204         lsr.rotateZ(45);
00205         drawScene();
00206 
00207          // *** AND IMPORTANT *** the FIRST time, we need to set the display engine (ie, attach the interrupt). This is not needed afterwards, ONLY if we change the scene.
00208           lsr.startDisplay();
00209 
00210         // (4) Main loop:
00211         // Change the POSE when necessary (also called "viewing transformation" or "global modelview" in OpenGL jargon), render and display:
00212         while (1) {
00213 
00214             if (pc.readable())
00215                 processSerial(); // here, the pose can be changed by a pc command
00216             hardwareKnobs();
00217 
00218             if (0) { //((t.read_ms()-lastTimeCreated)>10) {
00219                 // for tests:
00220                 myLed2 = !myLed2;
00221 
00222                 angle += 1;
00223                 if (angle > 360)
00224                     angle = 0;
00225 
00226                 // Set the current global pose:
00227                // lsr.setIdentityPose(); // we set the identity - then we don't need to do push pop... we start from "scratch" here. Not incremental rotation...
00228                // lsr.translate(0, 0, 1000);
00229                // lsr.rotateZ(angle);
00230                // lsr.rotateX(2.5 * angle);
00231 
00232                 lsr.setOrthoProjection();
00233                 lsr.setIdentityPose();
00234                 lsr.translate(CENTER_AD_MIRROR_X, CENTER_AD_MIRROR_Y, 0);
00235                 lsr.rotateZ(angle);
00236                // lsr.rotateY( angle);
00237 
00238                 // Then, render (and display) the whole scene (note: we DEFINITELY don't want to call this all the time, only when the RT matrix changes)
00239                 drawScene();
00240 
00241                 lastTimeCreated = t.read_ms();
00242             } // end auto-change pose loop
00243 
00244             if ((t.read_ms() - lastTimeSensed) > 50) { // check data sensing every xx ms
00245                 // Check objects and change colors or other properties as a function of the touch:
00246                 // NOTE: the testing #define debugDelayMirrors should not be defined in the laserSensingDisplay.h
00247                 // (note: we assume we are drawing the text).
00248                 // There are two ways to query for an object input: using the ID, or from its pointer (scene->objectArray[i]) if we know it. This is faster.
00249                 for (int i = 0; i < scene.totalObjects(); i++) {
00250                     BaseObject* ptrObj = scene.objectArray[i];
00251                     if (ptrObj->sense()) { // this calls to ptrObj->displaySensingBuffer.processSensedData()
00252                         ptrObj->setColor(0x02);
00253 
00254                         // char str[15];
00255                         // sprintf(str, "%d", touchedTimes);
00256                         // textToDisplay=string(str);//string(itoa(touchedTimes));
00257                         // touchedTimes++;
00258                         // createTextScene();
00259 
00260                     } else
00261                         ptrObj->setColor(0x01);
00262                 }
00263                 lastTimeSensed = t.read_ms();
00264             } // end sensing loop
00265 
00266         } // "end" infite loop
00267           // =================================
00268     */
00269 
00270     // EXAMPLE 2: 3d text  ======================================================
00271 
00272     // (1) Calibration matrices:
00273     // Typically, the projection and extrinsic matrix is set from the PC side, or loaded by default (from file system).
00274     lsr.loadProjMatrix(K1, scaleFactorProjector1); // we could use a wrapper, but I won't for the time being.
00275     lsr.loadExtrinsicsMatrix(E1);
00276 
00277     // (2) Create the scene in "local" coordinates:
00278     createTextScene(); // Clear scene, and create a default scene (for tests), and update scene (but not yet rendered)
00279 
00280    // (3) Set a default PERSPECTIVE and GLOBAL POSE for start displaying:
00281     lsr.loadProjMatrix(K1, scaleFactorProjector1);
00282     lsr.setIdentityPose();
00283     lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00284 
00285     // DEFAULT position in CAMERA coordinates (calibration was in cm):
00286     lsr.translate(0, 0, 130);
00287 
00288      drawScene(); // this will be called when we change the pose matrix - but needs to be called at least once to start displaying
00289      updateScene(); // this is important: this will compute the number of objects, points, etc, to prepare the displaying engine (but rendering is NOT yet done,
00290     // rendering is done in the drawScene() function.
00291     // *** AND IMPORTANT *** the FIRST time, we need to set the display engine (ie, attach the interrupt). This is not needed afterwards, ONLY if we change the scene.
00292     
00293     startDisplay();
00294 
00295     // Add more text (testing):
00296   //   textToDisplay="1";
00297   //   addText();
00298      
00299       // (3) Set a default PERSPECTIVE and GLOBAL POSE for start displaying:
00300   //  lsr.loadProjMatrix(K1, scaleFactorProjector1);
00301   //  lsr.setIdentityPose();
00302   //  lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00303     // DEFAULT position in CAMERA coordinates (calibration was in cm):
00304   //  lsr.translate(0, 0, 130);
00305      
00306    //  drawScene(); 
00307    //  updateScene();
00308 
00309     // (4) Main loop:
00310     while(true) {
00311 
00312         // =========== Query hardware events (knobs, ethernet, serial port) ============
00313        #ifdef WITH_OSC
00314         Net::poll(); // This polls the network connection for new activity, without keeping on calling this you won't receive any OSC!
00315         #endif
00316         
00317         if (pc.readable()) processSerial(); // here, the pose can be changed by a pc command
00318         hardwareKnobs();
00319         // =============================================================================
00320 
00321         // Automatic change of pose for tests
00322         if (0) {//(t.read_ms()-lastTimeCreated)>20) {
00323             angle+=.2;
00324             if (angle>360) angle=0;
00325 
00326             lsr.setIdentityPose(); // we set the identity - then we don't need to do push pop... we start from "scratch" here. Not incremental rotation...
00327             lsr.flipY();
00328             lsr.translate(0,0,1000);
00329             lsr.rotateZ(angle);
00330             //lsr.rotateX(angle);
00331 
00332             drawScene();
00333 
00334             lastTimeCreated=t.read_ms();
00335         }
00336 
00337         if ((currentSensingMode!=NO_SENSING)&&((t.read_ms()-lastTimeSensed)>70)) { // check data sensing every xx ms
00338             // Check objects and change colors or other properties as a function of the touch:
00339             // NOTE: the testing #define debugDelayMirrors should not be defined in the laserSensingDisplay.h
00340             // (note: we assume we are drawing the text).
00341             // There are two ways to query for an object input: using the ID, or from its pointer (scene->objectArray[i]) if we know it. This is faster.
00342             switch(currentSensingMode) {
00343                 case SENSING_WHOLE_SCENE: // Sensing whole scene ----------
00344                     if (scene.sense())   {
00345 
00346                         // COUNTING:
00347                         // char str[15];
00348                         //  sprintf(str, "%d", touchedTimes);
00349                         //  textToDisplay=string(str);//string(itoa(touchedTimes));
00350                         //  touchedTimes++;
00351                         //  createTextScene();
00352                         // (3) Set a default PERSPECTIVE and GLOBAL POSE for start displaying:
00353                         // lsr.loadProjMatrix(K1, scaleFactorProjector1);
00354                         // lsr.setIdentityPose();
00355                         // lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00356                         // This means that the current coordinate frame is the CAMERA, and calibration was in cm:
00357                         // lsr.translate(0, 0, 100);
00358                         ////lsr.flipY();
00359                         // drawScene(); // this will be called when we change the pose matrix - but needs to be called at least once to start displaying
00360                         // }
00361                     }
00362                     break;
00363                 case SENSING_PER_OBJECT: // Per-object sensing and action:
00364                     for (int i=0; i<scene.totalObjects(); i++) {
00365                         BaseObject* ptrObj=scene.objectArray[i];
00366                         if (ptrObj->sense()) { // this calls to ptrObj->displaySensingBuffer.processSensedData()
00367                             ptrObj->setColor(0x02); // make it green
00368 
00369                             // for fun: let's rotate THIS letter:
00370                             //lsr.pushPoseMatrix();
00371                             //lsr.setIdentityPose();
00372                             //lsr.rotateX(180);
00373                             //transformObject(ptrObj);
00374                             //lsr.popPoseMatrix();
00375                             // we need to redraw the scene (ie, reproject), or at least this object:
00376                             //lsr.renderObject(ptrObj, lsr.RT);
00377 
00378                             // or "highlight" the object by putting "cartouche" around it object (note: do this only if it did NOT have
00379                             //addCartoucheObject(ptrObj);
00380 
00381                              //pc.putc(ptrObj->ID());
00382                              //pc.printf("%d \n", ptrObj->ID());
00383                              pc.printf("%d", ptrObj->ID());
00384                         } else
00385                             ptrObj->setColor(0x01); // make it blue
00386                     }
00387                     break;
00388                 default:
00389                     break;
00390             }
00391             lastTimeSensed=t.read_ms();
00392         } // end sensing
00393 
00394     } // infinite while loop
00395     // =================================
00396 }
00397 
00398 void setOrthographicView()
00399 {
00400     // clearScene();
00401     // set color:
00402     lsr.setColor(0x02); // green
00403     //IO.setLaserLockinPower(0); // DISABLING SENSING LASER! (here the red). This is FOR CALIBRATION laser-camera
00404 
00405     lsr.setOrthoProjection();
00406     lsr.setIdentityPose(); // we could have done the translation here instead of in "local coordinates", but it's the same.
00407 }
00408 
00409 void createSceneTest()
00410 {
00411     lsr.pushPoseMatrix();
00412 
00413     // (1) Clear the scene (this stops displaying, thus creating a "laser hot spot", but in principle it only happens in the setup)
00414     clearScene(); // NOTE: in the future (and if we have enough RAM, we can have several indexed "scenes", instead of a unique global)
00415 
00416     // (2) Set displaying attributes (colors and local pose):
00417     // (a) Set the "local pose" (i.e., the MODELING TRANSFORMATION in OpenGL jargon):
00418     lsr.setIdentityPose(); // we could use a wrapper, but I won't for the time being.
00419     // (b) set color:
00420     lsr.setColor(0x02);
00421 
00422     // Add a first object: using openGL-like syntaxis (here, a closed square):
00423     // begin(1); // start creating object with identifier = 1
00424     //  vertex(10,10,1);
00425     //  vertex(10,100,1);
00426     //  vertex(100,100,1);
00427     //  vertex(10,100,1);
00428     //  vertex(10,10,1); //
00429     // end();
00430 
00431     // Add another objects using "object primitives":
00432     //begin(2);
00433     //lsr.translate(-100,-100,0); // recenter the square
00434     //square(200, 10); // this square has a corner in (0,0), and by default, z=0
00435     //end();
00436 
00437     // A "cube" (with one corner at the origin):
00438     //begin(3);
00439     //lsr.setIdentityPose(); // we set the identity - then we don't need to do push pop... we start from "scratch" here. Not incremental rotation...
00440     //lsr.translate(100,-100,-100); // recenter the cube (no need to push pop because we are seting the identity above)
00441     //lsr.rotateY(30);
00442     //cube(200,10); // cube(200, 20);
00443     //end();
00444 
00445     // A grid:
00446     // IMPORTANT: a grid is a multi-object built, and DOES NOT NEED to be between a begin and end
00447     lsr.setIdentityPose(); // we set the identity - then we don't need to do push pop... we start from "scratch" here. Not incremental rotation...
00448     lsr.translate(-500, -500, 0);
00449     grid(1000, 1000, 5, 5, 1); //grid(float sizeX, float sizeY, int nx, int ny, int repeatpoint);
00450     //gridCircles(300, 250, 6, 5, 10, 6); // gridCircles(float sizeX, float sizeY, int nx, int ny, float radius, int nbpointsCircle)
00451 
00452     // A circle:
00453     //begin(4);
00454     //circle(200, 100);
00455     //end();
00456 
00457     updateScene(); // this is important: this will compute the number of objects, points, etc, to prepare the displaying engine (but rendering is NOT yet done,
00458     // rendering is done in the drawScene() function.
00459 
00460     // pc.printf("Number of objects in the scene: %d\n", scene.totalObjects());
00461     // pc.printf("Number of points in the scene: %d\n", scene.totalPoints());
00462 
00463     lsr.popPoseMatrix();
00464 }
00465 
00466 void createTextScene()
00467 {
00468     lsr.pushPoseMatrix();
00469     //This function just creates text in local coordinates. We have two options: to create it as a unique object, or as separate objects (one per letter).
00470     // The first option is simpler now, we just use the wrapper function string3d(string _text, float totalWidth, float height):
00471 
00472     // (1) Clear the scene (this stops displaying, thus creating a "laser hot spot", but in principle it only happens in the setup)
00473     clearScene(); // NOTE: in the future (and if we have enough RAM, we can have several indexed "scenes", instead of a unique global)
00474 
00475     // (2) Set displaying attributes (colors and pose):
00476     // (a) Set the "local pose" (i.e., the MODELING TRANSFORMATION in OpenGL jargon):
00477     lsr.setIdentityPose(); // we could use a wrapper, but I won't for the time being.
00478     //lsr.flipY();
00479     //lsr.translate(2,6,0);
00480 
00481     lsr.flipY();
00482     lsr.flipX();
00483     lsr.translate(-15,-10,0);
00484 
00485     // (b) set current color:
00486     lsr.setColor(0x04); // three LSB bits for RGB - so 0x02 is GREEN ON (note that the sensing laser, now red, is always on...).
00487 
00488     // A string as a UNIQUE object:
00489     // begin(1); // start creating an object with index 1
00490     // no retouching of the modelview, meaning the text is in (0,0,0) in "local" coordinates
00491     //    string3d(textToDisplay, textToDisplay.size()*fontWidth, fontHeight);
00492     //end();
00493 
00494     // A string as a *collection* of object-letters:
00495     //lsr.translate(-textToDisplay.length()*fontWidth/2,-fontHeight/2,0);
00496     for (unsigned short i = 0; i < textToDisplay.length(); i++) {
00497         char ch = textToDisplay.at(i);
00498         if (ch != ' ') {
00499             begin(i);
00500             letter3d(ch, fontWidth, fontHeight);
00501             end();
00502         }
00503         lsr.translate(1.1*fontWidth, 0, 0);
00504     }
00505 
00506     lsr.popPoseMatrix();
00507 
00508 }
00509 
00510 void addText(string text, int id, float posx, float posy)
00511 {
00512     //clearScene();
00513     lsr.pushPoseMatrix();
00514     //This function just creates text in local coordinates. We have two options: to create it as a unique object, or as separate objects (one per letter).
00515     // The first option is simpler now, we just use the wrapper function string3d(string _text, float totalWidth, float height):
00516 
00517     // (1) Clear the scene (this stops displaying, thus creating a "laser hot spot", but in principle it only happens in the setup)
00518     // clearScene(); // NOTE: in the future (and if we have enough RAM, we can have several indexed "scenes", instead of a unique global)
00519 
00520     // (2) Set displaying attributes (colors and pose):
00521     // (a) Set the "local pose" (i.e., the MODELING TRANSFORMATION in OpenGL jargon):
00522     lsr.setIdentityPose(); // we could use a wrapper, but I won't for the time being.
00523     //lsr.flipY();
00524     //lsr.translate(2,6,0);
00525 
00526     lsr.flipY();
00527    // lsr.flipX();
00528     lsr.translate(posx,posy,0);
00529 
00530     // (b) set current color:
00531     lsr.setColor(0x04); // three LSB bits for RGB - so 0x02 is GREEN ON (note that the sensing laser, now red, is always on...).
00532 
00533     // A string as a UNIQUE object:
00534     // begin(1); // start creating an object with index 1
00535     // no retouching of the modelview, meaning the text is in (0,0,0) in "local" coordinates
00536     //    string3d(textToDisplay, textToDisplay.size()*fontWidth, fontHeight);
00537     //end();
00538 
00539     // A string as a *collection* of object-letters:
00540     //lsr.translate(-textToDisplay.length()*fontWidth/2,-fontHeight/2,0);
00541      
00542     for (unsigned short i = 0; i < text.length(); i++) {
00543         char ch = text.at(i);
00544         if (ch != ' ') {
00545           begin(id);
00546             letter3d(ch, fontWidth, fontHeight);
00547         end();
00548         }
00549         lsr.translate(1.1*fontWidth, 0, 0);
00550     }
00551     lsr.popPoseMatrix();
00552 
00553 }
00554 
00555 // ============ COMMUNICATION PROTOCOL ======================================
00556 // String to store ALPHANUMERIC DATA (i.e., integers, floating point numbers, unsigned ints, etc represented as DEC):
00557 // TO DO: use string objects!
00558 char receivedStringData[24]; // note: an integer is two bytes long, represented with a maximum of 5 digits, but we may send floats or unsigned int...
00559 int indexStringData = 0; //position of the byte in the string
00560 
00561 // String to store COMMAND WORDS (not used yet):
00562 char stringCommand[24];
00563 int indexStringCommand = 0;
00564 bool commandReady = false; // will become true when receiving the byte 0 (i.e. the '/0' string terminator)
00565 
00566 
00567 #ifdef WITH_OSC
00568 //============= RECEIVE OSC COMMANDS =========================
00569 // This is the callback function called when there are packets on the listening socket. It is not nice to have it
00570 // here, but for the time being having a "wrapping global" is the simplest solution (we cannot pass a member-function pointer
00571 // as handler to the upd object).
00572 void processOSC(UDPSocketEvent e)
00573 {
00574     osc.onUDPSocketEvent(e);
00575 
00576     if (osc.newMessage) {
00577 
00578       //  pc.printf("RECEIVED NEW OSC MESSAGE ----\n");
00579 
00580         // Acquire the addresses and arguments and put them in the GLOBAL variables to be processed by the interpretCommand function (common to serial and OSC):
00581         command1="";
00582         command2="";
00583         for (int i=0; i<recMes.getAddressNum(); i++)  {
00584             strcpy(address[i],recMes.getAddress(i)); // NOTE: up to the rest of the program to check if address[1] is really not null
00585           //  pc.printf("Address %d = %s \n",i, address[i]);
00586         }
00587         // Acquire data:
00588 
00589         numArgs=recMes.getArgNum();
00590         data[0]=-1;
00591         data[1]=-1;
00592         for (int i=0; i<numArgs; i++) {
00593             data[i]=(int)recMes.getArgInt(i);//recMes.getArgFloat(i);
00594             //pc.printf("%4.2f %4.2f \n", data[i], recMes.getArgFloat(i));
00595            // pc.printf("%i %i \n", data[i], recMes.getArgInt(i));
00596         }
00597 
00598         // Finally, interpret the command or data:
00599         interpretCommand();
00600 
00601     }
00602 }
00603 #endif
00604 
00605 
00606 //interpretCommand(const char& address[2][], const int& data[2]) {
00607 void interpretCommand()
00608 {
00609     // ==========  DATA (all this is a hack because my OSC class does not accept BUNDLES...) =============
00610     // Add data to auxiliary data buffer:
00611     if (command1 == "data") {
00612         // numArgs is the number of arguments (in my OSC version this is max 2):
00613      //   pc.printf("--- Data pack: %d\n", numArgs);
00614         for (int i=0; i<numArgs; i++) {
00615             auxDataBuffer[auxDataBuffer_index+i] = 1.0*data[i];
00616             // note: the index will be reset to 0 or whatever needed when a command USING data from the "d" message is received.
00617      //       pc.printf("buffer index / data: %i %f \n", auxDataBuffer_index+i, auxDataBuffer[auxDataBuffer_index+i]);//data[i]);
00618         }
00619         auxDataBuffer_index+=numArgs;
00620         //pc.putc('/n');
00621     }
00622     // ========== COMMANDS (using data on auxDataBuffer or directly as arguments =========================
00623 
00624     else if (command1 == "objectID") { // ID of the object
00625             receivedStringData[indexStringData] = 0;
00626             indexStringData = 0;
00627             objectID=atoi(receivedStringData);
00628        }
00629 
00630     else if (command1 == "mbedReset" ) mbed_reset();
00631 
00632     else if (command1 == "testPower" ) {
00633         // TO DO
00634     }
00635 
00636     // Enable/disable projection:
00637     else if ( command1 == "stopDisplay" ) stopDisplay();
00638     else if (command1 =="resumeDisplay")  resumeDisplay();
00639     else if (command1 =="showLimits") showLimitsMirrors(50, 1);
00640     else if (command1 == "setSensingMode") {
00641         int value=data[0];
00642         if (value!=-1) { // otherwise do nothing, this is a reception error (there was no data)
00643             switch(value) {
00644                 case 0:
00645                     currentSensingMode=NO_SENSING;
00646                     break;
00647                 case 1:
00648                     currentSensingMode=SENSING_WHOLE_SCENE;
00649                     break;
00650                 case 2:
00651                     currentSensingMode=SENSING_PER_OBJECT;
00652                     break;
00653                 default:
00654                     break;
00655             }
00656         }
00657     }
00658 
00659     // Change state machine color (objects created from this point on will have the state machine color)
00660     else if (command1 == "setStateColor") { // example: 0( (all OFF), 1( blue ON, 2( green ON, 4( red ON, 3( blue and green ON; etc.
00661         int value=data[0];
00662         if (value!=-1) lsr.setColor(value);
00663     }
00664 
00665     // Real time change of color of ALL the objects in the CURRENT scene (state machine color not changed)
00666     else if (command1 == "setAllObjectsColor") { // example: 0) (all OFF), 1) blue ON, 2) green ON, 4) red ON, 3) blue and green ON; etc.
00667         int value=data[0];
00668         if (value!=-1) changeColorScene(value);
00669     }
00670 
00671 
00672 // ===================  CREATION and DESTRUCTION of objects =====================================================
00673     else if (command1 == "clearScene") {
00674         clearScene();
00675     }
00676 
00677     else if (command1 =="deleteObject") { // second address is object identifier (a string that will be converted
00678         deleteObject(objectID);
00679     }
00680     
00681        else if (command1=="initialPosition") { // this is for setting the POSITION of the object to be created (or displacement):
00682            xx=auxDataBuffer[0]; yy=auxDataBuffer[1];
00683            auxDataBuffer_index=0;
00684        }
00685     
00686 // ===================  TRANSFORMATION OF OBJECT POINTS =========================================================
00687 // NOTE: this may in the end destroy the object rigidity because approximations... but without an RT per object, this is the only way to 
00688 // modify object pose independently of the whole scene...
00689 else if (command1 =="moveObject") {
00690        translateObject(objectID,  xx,  yy, 0);
00691     }
00692 
00693 
00694 // ==============================================================================================================
00695 
00696 
00697     // Produce a grid of points. The projection is ORTHOGRAPHIC. Also, POSE is reset to identity (i.e., the sent points should have
00698     // been translated previously - this may be optional, we could first send the pose, then the points...)
00699     // Note: orthographic projection can be achieved by simply setting the projection matrix to ID, while
00700     // setting Z to 1, or by setting the projection matrix to a unit diagonal but the last term in the diagonal is set to 0.
00701     // Finally, if one wants to avoid an unnecessary matrix product, the laserRendering class provides a renderingMode that can be set to RAW.
00702     // NOTE: the following string of ASCII characters is assumed to have been input:
00703     //               posX#posY#sizeX#sizeY#nx#ny#:
00704     // where the names (ex: posX) is in fact an ASCII string representing the number in decimal base. This means that when we arrive here,
00705     // the auxiliary array auxDataBuffer contains all that data (as floats), ex: auxDataBuffer[0] is just posX, and auxDataBuffer[5] is ny
00706     else if (command1 =="gridScene") {
00707         // Data is now ordered in the auxDataBuffer array:
00708         float posX = auxDataBuffer[0], posY = auxDataBuffer[1], sizeX = auxDataBuffer[2], sizeY = auxDataBuffer[3], nx = auxDataBuffer[4], ny = auxDataBuffer[5];
00709         auxDataBuffer_index=0; // to restart loading the auxiliary buffer 'auxDataBuffer'
00710         clearScene();
00711         // set color:
00712         lsr.setColor(0x02); // green
00713         //IO.setLaserLockinPower(0); // DISABLING SENSING LASER! (here the red). This is FOR CALIBRATION laser-camera
00714 
00715         // set local pose matrix to identity:
00716         lsr.setIdentityPose();
00717         // translate to the required position:
00718         lsr.translate(posX, posY, 0); // since the projection  and pose are going to be set
00719         // to Identity (projection identity will automatically make the projection orthographic), this means that these
00720         // values are in "laser projector pixels" (in fact angles).
00721         // Create the collection of dot objects:
00722         // void grid(float sizeX, float sizeY, int nx, int ny, int repeatpoint);
00723         grid(sizeX, sizeY, nx, ny, 1);
00724         updateScene(); // this is important: this will compute the number of objects, points, etc, to prepare the displaying engine (but rendering is NOT yet done,
00725         // rendering is done in the drawScene() function.
00726 
00727         // Now we can render the scene once:
00728         // Set a default GLOBAL POSE and orthographic projection for rendering and start displaying:
00729         lsr.setOrthoProjection();
00730         lsr.setIdentityPose(); // we could have done the translation here instead of in "local coordinates", but it's the same.
00731         drawScene(); // this will be called when we change the pose matrix - but needs to be called at least one to start displaying
00732     }
00733     // NOTE: now that the grid is set, we don't need to do it again when changing the pose: JUST SEND THE POSE MATRIX and things will be re-rendered!
00734 
00735     // This means we received "2D" vertex data (z assumed 0) to create A SINGLE SCENE out of these points (we will create a single object)
00736     // using orthographic projection.
00737     // This is in particular useful to create "structured light" grids - such the grid of planar points for calibration.
00738     // In the future, we can have functions to add objects, etc. Basically, every wrapped function should be call-able by the PC.
00739     // NOTE: the POSE is reset to ID, but we could use the current pose (i.e., send it first by the computer). But for the time being, and in order to modify the
00740     // cameraProjectorCalibration Xcode project as little as possible, I will perform the transformations on the computer.
00741     else if (command1 == "arbitraryGridScene") {
00742         // Data is now ordered in the auxDataBuffer array as PAIRS (X,Y). The argument to this message is the IDENTIFIER of the object:
00743         // The present value of auxDataBuffer_index contains the number of points x 2
00744         clearScene();
00745         lsr.setIdentityPose();
00746         //lsr.setColor(0x02); // fixed color, or use the current color (in which case, we need to call lsr.pushColor() and then pop it again).
00747         lsr.setColor(0x03); // blue+green
00748         IO.setLaserLockinPower(0); // DISABLING SENSING LASER! (here the red). This is FOR CALIBRATION laser-camera
00749 
00750         // begin(1) // we can create a single object, or one object per position (with repetition of the point if needed)
00751         for (unsigned char i = 0; i < auxDataBuffer_index / 2; i++) {
00752             begin(i);
00753             for (unsigned char k=0; k<1; k++) // fixed repetition of points - we can send this as a parameter if we want.
00754                 vertex(auxDataBuffer[2 * i], auxDataBuffer[2 * i + 1], 0);
00755             end();
00756         }
00757         updateScene();
00758         // Set a default GLOBAL POSE and ORTHO projection matrix for start displaying, or use the CURRENT ONE (for that, we should have
00759         // properly called lsr.pushPoseMatrix())
00760         lsr.setOrthoProjection();
00761         lsr.setIdentityPose();
00762         drawScene();
00763         auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
00764     }
00765 
00766     // This means we received 2D vertex array to add an object assuming it's planar (we will create an object with all points having z=0 in current pose):
00767     else if (command1 == "createObject2D") {
00768         unsigned char numPoints= auxDataBuffer_index/2;
00769          if (objectID!=-1) {
00770 
00771                 // First, create the object:
00772                 lsr.pushPoseMatrix();
00773                 lsr.setIdentityPose();
00774                 lsr.translate(xx,yy,0);
00775 
00776                 lsr.setColor(0x02); // we will render in current color
00777 
00778                 begin(objectID);
00779                 for (unsigned char i = 0; i < numPoints; i++) {
00780                     begin(i);
00781                     vertex(auxDataBuffer[2 * i], auxDataBuffer[2 * i + 1],0); // z=0 for 2d objects (in current pose)
00782                     //letter3d('A', fontWidth, fontHeight);
00783                     //vertex(10*cos(2*PI/numPoints*i), 10*sin(2*PI/numPoints*i), 0);
00784                     //vertex(5*cos(2*PI/numPoints*i+.1), 5*sin(2*PI/numPoints*i+.1), 0);
00785                     //pc.printf("local (x,y): %f, %f \n", auxDataBuffer[2 * i],  auxDataBuffer[2 * i+1]);
00786                     // lsr.translate(1.1*fontWidth, 0, 0);
00787                 }
00788                 end();
00789                 lsr.popPoseMatrix();
00790 
00791                 // Set the global projection and modelview:
00792                 lsr.loadProjMatrix(K1, scaleFactorProjector1);
00793                 lsr.setIdentityPose();
00794                 lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00795                 // DEFAULT position in CAMERA coordinates (calibration was in cm):
00796                 lsr.translate(0, 0, 130);
00797 
00798                 // RENDER the scene:
00799                // update the scene for display
00800                 drawScene();
00801                 updateScene();
00802             }
00803     }
00804 
00805     // This means we received 3D vertex data to create an object.
00806     // It will be rendered in the CURRENT pose.
00807     else if (command1 == "createObject3D") {
00808         int objectID=data[1];
00809         if (objectID!=-1) {
00810             // Data is now ordered in the auxDataBuffer array in triplets (X,Y,Z).
00811             // The present value of auxDataBuffer_index contains the number of points x 3
00812             //lsr.pushPoseMatrix(); // we will render on the current pose
00813             //clearScene();
00814             //lsr.setIdentityPose();
00815             //lsr.setColor(0x02); // we will render in current color
00816             begin(objectID);
00817             for (unsigned char i = 0; i < auxDataBuffer_index / 3; i++) {
00818                 vertex(auxDataBuffer[3 * i], auxDataBuffer[3 * i + 1],
00819                        auxDataBuffer[3 * i + 2]);
00820             }
00821             end();
00822             updateScene();
00823             // Set a default GLOBAL POSE and ORTHO projection matrix for start displaying, or use the CURRENT ONE (for that, we should have
00824             // properly called lsr.pushPoseMatrix())
00825             //lsr.setOrthoProjection();
00826             //lsr.setIdentityPose(); // we could have done the translation here instead of in "local coordinates", but it's the same.
00827             //lsr.popPoseMatrix();
00828             drawScene();
00829             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
00830         }
00831     }
00832     
00833       else if (command1=="createText") {
00834             receivedStringData[indexStringData] = 0; // termination for the string
00835             indexStringData = 0;
00836             // Serial.println(receivedStringData);
00837             textToDisplay = string(receivedStringData);
00838            
00839            if (firstTimeDisplay) {clearScene(); firstTimeDisplay=false;}
00840            
00841            addText(textToDisplay, objectID, xx, yy);
00842            drawScene();
00843            updateScene();
00844         }
00845 
00846     // Create text:
00847     else if (command1 == "createTextObject") {
00848 
00849         if (objectID!=-1) {
00850 
00851             // CREATE OBJECT:
00852             lsr.pushPoseMatrix();
00853             lsr.setIdentityPose(); // we could use a wrapper, but I won't for the time being.
00854             lsr.flipY();
00855             //lsr.flipX();
00856             lsr.translate(xx,yy,0);
00857 
00858             begin(objectID);
00859             for (unsigned short i = 0; i < textToDisplay.length(); i++) {
00860                 char ch = textToDisplay.at(i);
00861                 if (ch != ' ') {
00862                    // begin(i);
00863                     letter3d(ch, fontWidth, fontHeight);
00864                    // end();
00865                 }
00866                 lsr.translate(1.1*fontWidth, 0, 0);
00867             }
00868             end();
00869 
00870             lsr.popPoseMatrix();
00871 
00872             // Set a default PERSPECTIVE and GLOBAL POSE for start displaying:
00873             lsr.loadProjMatrix(K1, scaleFactorProjector1);
00874             lsr.setIdentityPose();
00875             lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00876             // DEFAULT position in CAMERA coordinates (calibration was in cm):
00877             lsr.translate(0, 0, 130);
00878 
00879             drawScene(); // this will be called when we change the pose matrix - but needs to be called at least once to start displaying
00880             updateScene();
00881         }
00882     }
00883 
00884 
00885     // (d) TERMINATOR indicating data was for the POSE MATRIX of the object (Mp) (with respect to the CAMERA):
00886     else if (command1 == "poseMatrix") { // when receiving this, it means that the WHOLE matrix data (4x4 values) have been sent in row/column format
00887         auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer'
00888         // Now, auxDataBuffer is a buffer with 12 values (4x3), corresponding to the pose of the object in CAMERA coordinartes (RT')
00889         lsr.setIdentityPose();               // RT=ID
00890         lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
00891         lsr.multPoseMatrix(auxDataBuffer); // RT=ExRT' : this sets RT as the current object pose in PROJECTOR coordinates
00892 
00893         drawScene(); // needed because we changed the POSE (but there is no need to re-create the geometry nor update the renderer (updateScene), just project)
00894     }
00895 
00896     // (d) TERMINATOR indicating data was for the projection matrix (will probably be saved in "hard" in the microcontroller code):
00897     else if (command1 == "projectionMatrix") {// when receiving this character, it means that the WHOLE matrix data (3x3 values) have been sent (with '#' separator), in row/column format
00898         auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
00899         // store in projection matrix:
00900         lsr.loadProjMatrix(auxDataBuffer, 1.0);
00901 
00902         drawScene(); // needed because we changed the PROJECTION matrix (but there is no need to re-create all the geometry, just project)
00903     }
00904 
00905     //(e) TERMINATOR indicating the data was for the extrinsic matrix:
00906     else if (command1 == "extrinsicMatrix")  { // when receiving this character, it means that the WHOLE matrix data (3x3 values) have been sent (with '#' separator), in row/column format
00907         auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
00908         // store in projection matrix:
00909         lsr.loadExtrinsicsMatrix(auxDataBuffer);
00910 
00911         drawScene(); // needed because we changed the EXTRINSICS (hence the pose), but there is no need to re-create the geometry, just project.
00912     }
00913 }
00914 
00915 void processSerial()
00916 {
00917     while (pc.readable() > 0) {
00918         char incomingByte = pc.getc();
00919 
00920         // For test:
00921         // pc.putc(incomingByte);
00922 
00923         // (a) TEXT to display or NUMBERS (in ASCII) to convert to numerical value (rem: limited set of characters for the time being):
00924         // Note: numbers are float, so we need also the "." and "-"
00925         if (       (incomingByte >= '0' && incomingByte <= '9')  // numbers
00926                    || (incomingByte >= 'A' && incomingByte <= 'Z')  // capital letters
00927                    || (incomingByte >= 'a' && incomingByte <= 'z')  // small letters (in fact, will be used for other symbols)
00928                    || (incomingByte == ' ') // space
00929                    || (incomingByte == '-') // minus sign
00930                    || (incomingByte == '.') // decimal point
00931            ) {
00932             receivedStringData[indexStringData] = incomingByte;
00933             indexStringData++;
00934         }
00935 
00936         // (b) a NUMBER to convert to float and to add to the auxiliary data buffer:
00937         else if (incomingByte == '#') { // this means that we received a whole number to convert to float (but we don't know yet if it's for
00938             // the modelview, the projection matrix or some other data):
00939             receivedStringData[indexStringData] = 0;
00940             indexStringData = 0;
00941             // Serial.println(receivedStringData); // for tests
00942             // convert to float and store in auxiliary "matrix" array:
00943             auxDataBuffer[auxDataBuffer_index] = atof(receivedStringData);
00944             //Serial.println( auxDataBuffer[auxDataBuffer_index]); // for tests
00945             auxDataBuffer_index++;
00946         }
00947 
00948         // Enable/disable projection:
00949         else if (incomingByte == '}') {
00950             stopDisplay();
00951         } else if (incomingByte == '{') {
00952             resumeDisplay();
00953         }
00954 
00955         // Show maximum excursion of mirrors:
00956         else if (incomingByte == '*') {
00957             showLimitsMirrors(50, 1);
00958         }
00959 
00960         else if (incomingByte=='_') {
00961             clearScene();
00962         }
00963 
00964         else if (incomingByte == '+') {
00965             receivedStringData[indexStringData] = 0;
00966             indexStringData = 0;
00967             switch(atoi(receivedStringData)) {
00968                 case 0:
00969                     currentSensingMode=NO_SENSING;
00970                     break;
00971                 case 1:
00972                     currentSensingMode=SENSING_WHOLE_SCENE;
00973                     break;
00974                 case 2:
00975                     currentSensingMode=SENSING_PER_OBJECT;
00976                     break;
00977                 default:
00978                     break;
00979             }
00980         }
00981 
00982         // Performs a scan of the surface and send all the data serially (N>, with N the resolution of the scan)
00983         else if (incomingByte == '>') {
00984             receivedStringData[indexStringData] = 0;
00985             indexStringData = 0;
00986             //pc.printf("scan command issued¥n");
00987             scanSerial(atoi(receivedStringData));
00988         }
00989 
00990         // Recompute the LUT table
00991         else if (incomingByte == '<') {
00992             recomputeLookUpTable();
00993         }
00994 
00995         // Change state machine color (objects created from this point on will have the state machine color)
00996         else if (incomingByte == '(') { // example: 0( (all OFF), 1( blue ON, 2( green ON, 4( red ON, 3( blue and green ON; etc.
00997             receivedStringData[indexStringData] = 0;
00998             indexStringData = 0;
00999             // convert to integer and set the state machine color:
01000             lsr.setColor(atoi(receivedStringData));
01001         }
01002 
01003         // Real time change of color of ALL the objects in the CURRENT scene (state machine color not changed)
01004         else if (incomingByte == ')') { // example: 0) (all OFF), 1) blue ON, 2) green ON, 4) red ON, 3) blue and green ON; etc.
01005             receivedStringData[indexStringData] = 0;
01006             indexStringData = 0;
01007             // convert to integer and set the color:
01008             changeColorScene(atoi(receivedStringData));
01009         }
01010 
01011 
01012         // Produce a grid of points. The projection is ORTHOGRAPHIC. Also, POSE is reset to identity (i.e., the sent points should have
01013         // been translated previously - this may be optional, we could first send the pose, then the points...)
01014         // Note: orthographic projection can be achieved by simply setting the projection matrix to ID, while
01015         // setting Z to 1, or by setting the projection matrix to a unit diagonal but the last term in the diagonal is set to 0.
01016         // Finally, if one wants to avoid an unnecessary matrix product, the laserRendering class provides a renderingMode that can be set to RAW.
01017         // NOTE: the following string of ASCII characters is assumed to have been input:
01018         //               posX#posY#sizeX#sizeY#nx#ny#:
01019         // where the names (ex: posX) is in fact an ASCII string representing the number in decimal base. This means that when we arrive here,
01020         // the auxiliary array auxDataBuffer contains all that data (as floats), ex: auxDataBuffer[0] is just posX, and auxDataBuffer[5] is ny
01021         else if (incomingByte == ':') {
01022             // Data is now ordered in the auxDataBuffer array:
01023             float posX = auxDataBuffer[0], posY = auxDataBuffer[1], sizeX = auxDataBuffer[2], sizeY = auxDataBuffer[3], nx = auxDataBuffer[4], ny = auxDataBuffer[5];
01024             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
01025             clearScene();
01026             // set color:
01027             lsr.setColor(0x02); // green
01028             //IO.setLaserLockinPower(0); // DISABLING SENSING LASER! (here the red). This is FOR CALIBRATION laser-camera
01029 
01030             // set local pose matrix to identity:
01031             lsr.setIdentityPose();
01032             // translate to the required position:
01033             lsr.translate(posX, posY, 0); // since the projection  and pose are going to be set
01034             // to Identity (projection identity will automatically make the projection orthographic), this means that these
01035             // values are in "laser projector pixels" (in fact angles).
01036             // Create the collection of dot objects:
01037             // void grid(float sizeX, float sizeY, int nx, int ny, int repeatpoint);
01038             grid(sizeX, sizeY, nx, ny, 1);
01039             updateScene(); // this is important: this will compute the number of objects, points, etc, to prepare the displaying engine (but rendering is NOT yet done,
01040             // rendering is done in the drawScene() function.
01041 
01042             // Now we can render the scene once:
01043             // Set a default GLOBAL POSE and orthographic projection for rendering and start displaying:
01044             lsr.setOrthoProjection();
01045             lsr.setIdentityPose(); // we could have done the translation here instead of in "local coordinates", but it's the same.
01046             drawScene(); // this will be called when we change the pose matrix - but needs to be called at least one to start displaying
01047         }
01048         // NOTE: now that the grid is set, we don't need to do it again when changing the pose: JUST SEND THE POSE MATRIX and things will be re-rendered!
01049 
01050         // This means we received "2D" vertex data (z assumed 0) to create a single scene out of these points (we will create a single object)
01051         // using orthographic projection.
01052         // This is in particular useful to create "structured light" grids - such the grid of planar points for calibration.
01053         // In the future, we can have functions to add objects, etc. Basically, every wrapped function should be call-able by the PC.
01054         // NOTE: the POSE is reset to ID, but we could use the current pose (i.e., send it first by the computer). But for the time being, and in order to modify the
01055         // cameraProjectorCalibration Xcode project as little as possible, I will perform the transformations on the computer.
01056         else if (incomingByte == '@') { // ID of the object
01057             command1="objectID";
01058             interpretCommand();
01059        }
01060        
01061        else if (incomingByte == '[') {
01062         command1 =="deleteObject";
01063         interpretCommand();
01064        }
01065        
01066        else if (incomingByte == '}') {
01067         command1 =="moveObject";
01068        interpretCommand();; // xx, yy contains already the necessary displacement
01069     }
01070 
01071         
01072        else if (incomingByte == '~') { // this is for setting the POSITION of the object to be created:
01073             command1="initialPosition";
01074             interpretCommand();
01075        }
01076         
01077         
01078         else if (incomingByte == '=') { // Create 2d object:
01079             command1 = "createObject2D"; 
01080             interpretCommand();
01081         }
01082 
01083         // This means we received 3D vertex data to create a single scene out of these points (we will create a single object).
01084         // It will be rendered in the CURRENT pose.
01085         else if (incomingByte == ';') {
01086             // Data is now ordered in the auxDataBuffer array in triplets (X,Y,Z).
01087             // The present value of auxDataBuffer_index contains the number of points x 3
01088             lsr.pushPoseMatrix(); // we will render on the current pose...
01089             clearScene();
01090             lsr.setIdentityPose();
01091             //lsr.setColor(0x02);
01092             begin(1);
01093             for (unsigned char i = 0; i < auxDataBuffer_index / 3; i++) {
01094                 vertex(auxDataBuffer[3 * i], auxDataBuffer[3 * i + 1],
01095                        auxDataBuffer[3 * i + 2]);
01096             }
01097             end();
01098             updateScene();
01099             // Set a default GLOBAL POSE and ORTHO projection matrix for start displaying, or use the CURRENT ONE (for that, we should have
01100             // properly called lsr.pushPoseMatrix())
01101             //lsr.setOrthoProjection();
01102             //lsr.setIdentityPose(); // we could have done the translation here instead of in "local coordinates", but it's the same.
01103             lsr.popPoseMatrix();
01104             drawScene();
01105             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
01106         }
01107 
01108 
01109         /*
01110          else if (incomingByte=='!') { // sets the width of the letter
01111          receivedStringData[indexStringData]=0;
01112          indexStringData=0;
01113          fontWidth=atof(receivedStringData);
01114          createTextScene(); // needed because we changed the geometry
01115          }
01116 
01117          else if (incomingByte=='"') { // sets the height of the letter
01118          receivedStringData[indexStringData]=0;
01119          indexStringData=0;
01120          fontHeight=atof(receivedStringData);
01121          createTextScene(); // needed because we changed the geometry
01122          }
01123          */
01124 
01125         // (c) TERMINATOR indicating the data was text to display:
01126         else if (incomingByte == '"') { // this means that the previous data was TEXT to display
01127             command1="createText";
01128             interpretCommand();
01129             }
01130 
01131         // (d) TERMINATOR indicating data was for the POSE MATRIX of the object (Mp) (with respect to the CAMERA):
01132         else if (incomingByte == '$') { // when receiving this character, it means that the WHOLE matrix data (4x4 values) have been sent (with '#' separator), in row/column format
01133             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
01134             // Now, auxDataBuffer is a buffer with 12 values (4x3), corresponding to the pose of the object in CAMERA coordinartes (RT')
01135             lsr.setIdentityPose();               // RT=ID
01136             lsr.multPoseMatrix(lsr.EXTRINSICS);  // RT=E // we can simply do: lsr.setExtrinsicsPose()
01137             lsr.multPoseMatrix(auxDataBuffer); // RT=ExRT' : this sets RT as the current object pose in PROJECTOR coordinates
01138 
01139             drawScene(); // needed because we changed the POSE (but there is no need to re-create the geometry, just project)
01140 
01141             // Handshake:
01142             pc.putc(13);
01143         }
01144 
01145         // (d) TERMINATOR indicating data was for the projection matrix (will probably be saved in "hard" in the microcontroller code):
01146         else if (incomingByte == '%') { // when receiving this character, it means that the WHOLE matrix data (3x3 values) have been sent (with '#' separator), in row/column format
01147             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
01148             // store in projection matrix:
01149             lsr.loadProjMatrix(auxDataBuffer, 1.0);
01150 
01151             drawScene(); // needed because we changed the PROJECTION matrix (but there is no need to re-create all the geometry, just project)
01152         }
01153 
01154         //(e) TERMINATOR indicating the data was for the extrinsic matrix:
01155         else if (incomingByte == '&') { // when receiving this character, it means that the WHOLE matrix data (3x3 values) have been sent (with '#' separator), in row/column format
01156             auxDataBuffer_index = 0; // to restart loading the auxiliary buffer 'auxDataBuffer' through serial port
01157             // store in projection matrix:
01158             lsr.loadExtrinsicsMatrix(auxDataBuffer);
01159 
01160             drawScene(); // needed because we changed the EXTRINSICS (hence the pose), but there is no need to re-create the geometry, just project.
01161         }
01162 
01163     }
01164 }