home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / PCGLOVE / GLOVE / MIDIGL.ZIP / GLGRPH1.CPP next >
Text File  |  1992-10-27  |  15KB  |  580 lines

  1. //
  2. // GlGrph.cpp:
  3. //    Implementation of classes graphicsActor, XYZ, hand, and Rectangle.
  4. //
  5. // Purpose:
  6. //      Utilizing Borland's GDI toolkit to display the result,
  7. //    compute the approximate shape of the power glove in 3-D space.
  8. //
  9. // Author(s): Mark Pflaging   C-serve  70233,1552
  10. // Copyright 1992   Mark Thomas Pflaging
  11. //
  12. // Also see authorships in OOPGLOVE.DOC.
  13. // Date:    5/15/92 - 6/4/92
  14. //
  15. #include "glgrph.hpp"
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <conio.h>
  19. #include <mem.h>
  20. #include <math.h>
  21. #include "\ptk\asm\mcc.h"
  22. char * hand::title = "Graphics";
  23.  
  24. extern irq; //interface's Irq level for midi
  25. // extern oldx;
  26. // extern oldy;
  27. // extern oldz;
  28. extern oldnote;
  29. extern oldmidfinger;
  30. extern num_of_notes;
  31. extern numdiv;
  32. extern start_note;
  33. extern pitchbend_on;
  34.  
  35. void graphicsActor::eraseGlove()
  36. {
  37.     // erase old box.
  38.     oldData.erase(leaveTrails);
  39. }
  40.  
  41. // draw square cursor
  42. void graphicsActor::drawGlove(gloveDriver &gd)
  43. {
  44.     XYZ newRect;
  45.     newRect.scaleToGlove(gd);
  46.  
  47.     // prevent redundant drawing.
  48.     if ((newRect == oldData) && (gd.getFingers() == oldFingers))
  49.         return;
  50.  
  51.     if( drawn ) eraseGlove();
  52.  
  53.     newRect.rectangle();
  54.     newRect.displayGlove(gd, *this);
  55.     drawn = 1;
  56.  
  57.     oldData = newRect;         /* save pos'n for next erase */
  58.     oldFingers = gd.getFingers();
  59. }
  60.  
  61.  
  62. //functions by mick imfeld to use xyz and index finger to control midi
  63. // interface
  64. int midnote;
  65.  
  66. // splits up glove x range into selected number of notes,
  67. // starting with selected starting note
  68. int findnote(int midxval)
  69. {
  70. midnote=(((midxval+127)/numdiv)+start_note);
  71. return(midnote);
  72. }
  73. // this function sends the glove info to the midi interface
  74. // using functions from the Musicquest Programmer's Toolkit
  75. void send_midi(int midx, int midy, int midz, int midfinger)
  76. {
  77. int midvol_M;
  78. int midvol_L;
  79. int modu_vol;
  80. int midpitch_M;
  81. int midpitch_L;
  82. int modu_pitch;
  83.  
  84. //assign a note number to x value
  85. midnote=findnote(midx);
  86.  
  87. // check and see if note off, i.e. glove index finger closed
  88. // if closed and last sample also closed, update data and return
  89. // if closed and last sample open, send noteoff oldnote
  90. // if open and no change of value, update data and return
  91. // if open and change of value, send new info
  92. if ((!midfinger) && (!oldmidfinger)) {
  93. // oldx=midx;
  94. // oldy=midy;
  95. // oldz=midz;
  96.   mcc_put(0x90);
  97.   mcc_put(oldnote);
  98.   mcc_put(0);
  99.   mcc_put(0xB0);
  100.   mcc_put(0x7B);
  101.   mcc_put(0);
  102.   oldnote=midnote;
  103.     }
  104. else if (!midfinger) {
  105.   mcc_put(0x90);
  106.   mcc_put(oldnote);
  107.   mcc_put(0);
  108.     mcc_put(0xB0);
  109.   mcc_put(0x7B);
  110.   mcc_put(0);
  111.   oldnote=midnote;
  112.   oldmidfinger=midfinger;
  113.   }
  114. else {
  115. if (!oldmidfinger) {
  116.    mcc_put(0x90);
  117.   mcc_put(midnote);
  118.   mcc_put(127);
  119.  }
  120.  
  121. // check to see if same note is still playing
  122. if ((oldmidfinger) && (oldnote!=midnote)) {
  123.  mcc_put(0x90);
  124.   mcc_put(oldnote);
  125.   mcc_put(0);
  126.     mcc_put(0x90);
  127.   mcc_put(midnote);
  128.   mcc_put(127);
  129.   oldnote=midnote;
  130.   }
  131.  oldmidfinger=midfinger;
  132.   //send new pitch bend value
  133.      if (pitchbend_on)  {
  134.      midpitch_M=(midy + 127) / 2;
  135.   midpitch_L=0;
  136.   modu_pitch=(midy + 127) % 2;
  137.   if (modu_pitch) midpitch_L=64;
  138.   mcc_put(0xE0);
  139.   mcc_put(midpitch_L);
  140.   mcc_put(midpitch_M);
  141.   }
  142.   //send new main volume value
  143.   midvol_M=(midz + 70);
  144.   midvol_L=0;
  145.   modu_vol=(midz + 70) % 2;
  146.   if (modu_vol) midvol_L=64;
  147.   mcc_put(0xB0);
  148.   mcc_put(7);
  149.   mcc_put(midvol_M);
  150.  mcc_put(0xB0);
  151.   mcc_put(39);
  152.   mcc_put(midvol_L);
  153.  
  154. }  //end of if
  155.  
  156.  
  157.  
  158.  
  159. } //end send_midi -back to o2glove
  160.  
  161.  
  162.  
  163.  
  164. void XYZ::scaleToGlove( GloveData & gd )
  165. {
  166.     setValues(
  167.         (getmaxx()/2) + 2 * gd.getX(),     // compute X,Y center.
  168.         (getmaxy()/2) - 2 * gd.getY(),
  169.         30 + ( gd.getZ() ) );          // size prop. to Z.
  170.     setRectValues(x - z, y - z, x + z, y + z);
  171. }
  172.  
  173. void XYZ::displayGlove(gloveDriver &gd, hand & myHand)
  174. {
  175.     setThetaRad(((double)gd.getRotation() * 360.0 / 12.0) * M_PI / 180.0);
  176.     myHand.scaleRect(*this);
  177.     myHand.drawAll(gd);
  178. }
  179.  
  180. void XYZ::rectangle()
  181. {
  182.     setcolor( 15 );                  // draw new box
  183.     ::rectangle(left, top, right, bottom);
  184. }
  185.  
  186. void XYZ::erase(int leaveTrail)
  187. {
  188.     int erased[5 * 2] = {
  189.         right, top,  right, bottom,  left, bottom,  left, top,
  190.         right, top
  191.     };
  192.     setfillstyle(SOLID_FILL,/*EGA_BLACK*/0);
  193.     fillpoly( 5, erased);
  194.     if (!leaveTrail) {
  195.         setcolor(0);
  196.         ::rectangle(left, top, right, bottom);
  197.     }
  198.     setfillstyle(SOLID_FILL,EGA_LIGHTGRAY);
  199. }
  200.  
  201. // (This data is not as ugly as it looks!)
  202. // 100 x 100 is the size of the "Unit
  203. // rectangle".  The original image should
  204. // be scaled fit in this size.  See below.
  205.  
  206. int noFingers[] =
  207. {
  208.     // Hand with no fingers.  (11 coordinates)
  209.     40, 60,  40, 90,  80, 90,  80, 70,  70, 70,  70, 60,
  210.     60, 60,  60, 50,  50, 50,  50, 60
  211. };
  212.  
  213. int thumb[] =
  214. {
  215.     // Thumb part 1.  (5 coordinates)
  216.     30, 60,  30, 80,  40, 80,  40, 60,  30, 60,
  217.     // Thumb part 2
  218.     20, 60,  20, 70,  30, 70,  30, 60,  20, 60
  219. };
  220.  
  221. int index[] =
  222. {
  223.     // Index part 1.  (5 coordinates)
  224.     40, 40,  40, 60,  50, 60,  50, 40,  40, 40,
  225.     // Index part 2
  226.     40, 30,  40, 40,  50, 40,  50, 30,  40, 30,
  227.     // Index part 3
  228.     40, 20,  40, 30,  50, 30,  50, 20,  40, 20
  229. };
  230.  
  231. int middle[] =
  232. {
  233.     // For middle, same as index except add 10 to x, subtract 10 from y
  234.     // Middle part 1.  (5 coordinates)
  235.     50, 30,  50, 50,  60, 50,  60, 30,  50, 30,
  236.     // Middle part 2
  237.     50, 20,  50, 30,  60, 30,  60, 20,  50, 20,
  238.     // Middle part 3
  239.     50, 10,  50, 20,  60, 20,  60, 10,  50, 10
  240. };
  241.  
  242.  
  243. int ring[] =
  244. {
  245.     // Ring part 1.  (9 coordinates)
  246.     60, 40,  60, 60,  70, 60,  70, 70,  80, 70,
  247.     80, 50,  70, 50,  70, 40,  60, 40,
  248.  
  249.     // Ring part 2
  250.     60, 30,  60, 40,  70, 40,  70, 50,  80, 50,
  251.     80, 40,  80, 30,  70, 30,  60, 30,
  252.  
  253.     // Ring part 3
  254.     60, 20,  60, 30,  70, 30,  70, 40,  80, 40,
  255.     80, 30,  70, 30,  70, 20,  60, 20
  256. };
  257.  
  258. HandType handData[5] =
  259. {
  260.     { 1, 10, noFingers },
  261.     { 2,  5, thumb },
  262.     { 3,  5, index },
  263.     { 3,  5, middle },
  264.     { 3,  9, ring}
  265. };
  266.  
  267. // Note that the numGroups and pointsPerGroup attributes are "static"
  268. // and do not need to be copied for each instantiation, but the
  269. // HandType.data should be copied since the data is modified
  270. // before it is drawn.
  271. //
  272. // The only "hardwired" thing about this class is that it always
  273. // has five "elements":  the part of the hand with no fingers
  274. // protruding, the thumb, the index finger, the middle finger, and
  275. // the ring finger.
  276. //
  277. //  My data was BASED on the preceding version's data, but by no
  278. //  means is it a copy.  If you don't like how it looks, change it!!
  279. //  And send me your data if you please!!
  280. //
  281. // No need to bother to start from scratch, just copy the subarrays and
  282. // the handData data array, rename, and you're set!
  283. #define IntsPerPoint    2
  284. hand::hand(InitFile & ini) : fillMode(ini.find(title, "fillMode", 0)),
  285.     original(handData)
  286. {
  287.     for (int i = 0; i < 5; i ++)
  288.     {
  289.         int a = handData[i].numGroups;
  290.         int b = handData[i].pointsPerGroup * IntsPerPoint;
  291.         int * c = (data[i] = new int[a * b]);
  292.         // get it?
  293.         memcpy(c, handData[i].data, a * b * sizeof(int));
  294.     }
  295. }
  296.  
  297. double Rectangle::thetaRad;
  298.  
  299. void Rectangle::setThetaRad(double value)
  300. {
  301.     thetaRad = value;
  302. }
  303.  
  304. // scalePoint is the heart of the graphics processing.
  305. // It shapes the hand to fit the rectangle, and rotates
  306. // the hand based on user input.
  307.  
  308. // This function moves the hand to the specified coordinates.
  309. // And scales it by the specified amount.  The more stuff
  310. // we can stick into this loop, the better.
  311. // Please note that thetaRad, the rotation angle, should already have
  312. // been set.
  313. void Rectangle::scalePoint(double x, double y, int & new_x, int & new_y)
  314. {
  315.     // 100 x 100 is the size of the "Unit
  316.     // rectangle".
  317.  
  318.     if (!(((int)x == 50) && ((int)y == 50))) {
  319.         // FIRST!, take care of rotation.
  320.         x -= (double)50;
  321.         y -= (double)50;
  322.         double h = sqrt(x*x+y*y), oldTheta;
  323.         if (int(x)) {
  324.             oldTheta = atan2(y, x);
  325.         }
  326.         else oldTheta = ((y > 0) ? M_PI_2 : -M_PI_2);
  327.         x = h * cos(oldTheta + thetaRad) + (double)50;
  328.         y = h * sin(oldTheta + thetaRad) + (double)50;
  329.     }
  330.     // Here is where the scaling
  331.     // itself takes place.
  332.     new_x = (int)((x * (double)(right - left)
  333.             / (double)100.0) + (double)left);
  334.     new_y = (int)((y * (double)(bottom - top)
  335.             / (double)100.0) + (double)top);
  336.     return;
  337. }
  338.  
  339. void hand::scaleRect(Rectangle &scaler)
  340. {
  341.     int tmp, k, j;
  342.     for ( int i = Fingers::NoFinger; i < (Fingers::Ring + 1); i ++)
  343.     {
  344.         int a = original[i].numGroups;
  345.         int b = original[i].pointsPerGroup * IntsPerPoint;
  346.         int * c = data[i];
  347.         int * d = original[i].data;
  348.         // get it?
  349.         for (j = 0; j < a; j ++) {
  350.             for (k = 0; k < b; k += IntsPerPoint) {
  351.                 tmp = j * b + k;
  352.                 scaler.scalePoint((double)d[tmp],
  353.                     (double)d[tmp+1],
  354.                     c[tmp], c[tmp+1]);
  355.             }
  356.         }
  357.     }
  358. }
  359.  
  360. void hand::drawOne(Fingers::handParts index, int numParts)
  361. {
  362.     int numPoints = original[index].pointsPerGroup;
  363.  
  364.     for (int i = 0; i < numParts; i ++) {
  365.         fillpoly(numPoints, &(data[index][i * IntsPerPoint * numPoints]));
  366.     }
  367. }
  368.  
  369. void hand::drawAll(gloveDriver & gd)
  370. {
  371.     setfillstyle(fillMode, EGA_LIGHTGRAY);
  372. //    setcolor(EGA_LIGHTGRAY);
  373.     for (int i = Fingers::NoFinger; i < (Fingers::Ring + 1); i ++)  {
  374.         drawOne((Fingers::handParts)i, gd.findNumParts((Fingers::handParts)i));
  375.     }
  376. }
  377.  
  378. void graphicsActor::test(gloveDriver& gd)
  379. {
  380.     // Okay, so this code is a little messy.
  381.     // I'm going to clean it up.
  382.     static textActive = 0;
  383.     static keyDown = FALSE;
  384.     int realKey;
  385.  
  386.     // draw_glove_plot(gd);        // plot x,y positions
  387.     // Fix problem when key is held down.
  388.     if ((realKey = gd.getKeys()) == -1) {
  389.         keyDown = FALSE;
  390.     }
  391.     else {
  392.         if (keyDown) realKey = -1;
  393.         else keyDown = TRUE;
  394.     }
  395.     // press "1" to display help...
  396.     if( (realKey == 1) && !textActive) {
  397.         cleardevice();
  398.         displayHelp();
  399.         outtext("Press the GLOVE enter key to continue.");
  400.         textActive = 1;
  401.     }
  402.  
  403.     // ...and Enter to continue.
  404.     if( (realKey == -128) && textActive) {
  405.         cleardevice();
  406.         textActive = 0;
  407.     }
  408.  
  409.     // press "2" to toggle drawing of moving hand.
  410.     if( (realKey == 2)) {
  411.         gloveActive = !(gloveActive);
  412.         if (!gloveActive) eraseGlove();
  413.     }
  414.  
  415.     // press "3" to toggle drawing of nonmoving hand.
  416.     if( (realKey == 3)) {
  417.         handActive = !(handActive);
  418.         if (!handActive) eraseFingers();
  419.     }
  420.  
  421.     // press "4" to toggle info.
  422.     if( (realKey == 4)) {
  423.         infoActive = !(infoActive);
  424.         if (!infoActive) infoErase(0);
  425.     }
  426.  
  427.     // press "A" to toggle trails.
  428.     if( (realKey == 10)) {
  429.         leaveTrails = !(leaveTrails);
  430.     }
  431.  
  432.     // press "B" to clear screen.
  433.     if( (gd.getKeys() == 11)) {
  434.         cleardevice();
  435.     }
  436.  
  437.     if (!textActive) {
  438.         if (gloveActive)
  439.             drawGlove(gd);    // animate glove cursor
  440.         if (handActive)
  441.             drawFingers(gd);    // draw the nonmoving "hand"
  442.         if (infoActive)
  443.             infoDisplay(gd);
  444. //        gesture.sense(gd);    // wishful thinking.
  445. //        gesture.display();
  446.     }
  447. }
  448.  
  449. void graphicsActor::displayHelp()
  450. {
  451.     cleardevice();
  452.     // output a message
  453.     int x = getmaxx() / 2;
  454.     int y = 5; // getmaxy() / 2;
  455.     settextjustify(CENTER_TEXT, CENTER_TEXT);
  456.  
  457.     int height = textheight("Tq");
  458.     moveto(x,y+=height);
  459.     outtext("This program tests the Nintendo Power Glove");
  460.     moveto(x,y+=height);
  461.     outtext("when connected to an IBM PC parallel port.");
  462.     moveto(x,y+=height);
  463.     moveto(x-=(getmaxx()/4),y+=height);
  464.     settextjustify(LEFT_TEXT, TOP_TEXT);
  465.     moveto(x,y+=height);
  466.  
  467.     outtext("The following POWER GLOVE keys (NOT keyboard keys!)");
  468.     moveto(x,y+=height);
  469.  
  470.     outtext("have been defined:");
  471.     moveto(x,y+=height);
  472.  
  473.     outtext("1 - display this help screen");
  474.     moveto(x,y+=height);
  475.  
  476.     outtext("2 - toggle drawing of moving hand.");
  477.     moveto(x,y+=height);
  478.  
  479.     outtext("3 - toggle drawing of nonmoving hand.");
  480.     moveto(x,y+=height);
  481.  
  482.     outtext("4 - to toggle info display.");
  483.     moveto(x,y+=height);
  484.     moveto(x,y+=height);
  485.  
  486.     outtext("A - to toggle \"trails\" behind the rectangle (try it!)");
  487.     moveto(x,y+=height);
  488.     outtext("B - to clear screen.");
  489.     moveto(x,y+=height);
  490.  
  491.     outtext("Press any KEYBOARD key to exit the program.");
  492.     moveto(x,y+=height);
  493.     moveto(x,y+=height);
  494. }
  495.  
  496. #define LINES 4
  497. #define XOFF  20
  498. #define YOFF  25
  499. #define NUMSTART 17
  500. void graphicsActor::infoErase(int start)
  501. {
  502.     int unit_wid = textwidth("W");
  503.     int x = XOFF + unit_wid * start, y = YOFF;
  504.     static char hightxt[] = "Tq";
  505.     int height = textheight(hightxt);
  506.     int width = unit_wid * (33 - start);
  507.     setviewport(x, y, width + x, height * LINES + y, 1);
  508.     clearviewport();
  509.     setviewport(0, 0, getmaxx(), getmaxy(), 0);
  510. }
  511.  
  512. void graphicsActor::infoDisplay(gloveDriver & gd)
  513. {
  514.     char temp[255];
  515.     int height = textheight("Tq");
  516.     int width = textwidth("W");
  517.  
  518.     infoErase(NUMSTART);
  519.     int x = XOFF, y = YOFF;
  520.  
  521.     setcolor(EGA_LIGHTGRAY);
  522.     // print constant text:
  523.     moveto(x + width * 8, y);
  524.     outtext("X, Y, Z:");
  525.     // print rot, fingers, keys
  526.     moveto(x + width * NUMSTART, y);
  527.     sprintf(temp, "%4d, %4d, %4d",
  528.         gd.getX(), gd.getY(), gd.getZ());
  529.     outtext(temp);
  530.  
  531.     moveto(x,y+=height);
  532.     outtext(" Rotation, Keys:");
  533.     sprintf(temp, "  %2d,  %-2x %-3d",
  534.         gd.getRotation(), gd.getKeys(), gd.getKeys());
  535.     moveto(x + width * NUMSTART, y);
  536.     outtext(temp);
  537.  
  538.     moveto(x + width * 8, y += height);
  539.     outtext("Fingers:");
  540.     sprintf(temp, "  %2x, %2x, %2x, %2x",
  541.         gd.findNumParts(Fingers::Thumb),
  542.         gd.findNumParts(Fingers::Index),
  543.         gd.findNumParts(Fingers::Middle),
  544.         gd.findNumParts(Fingers::Ring));
  545.     moveto(x + width * NUMSTART, y);
  546.     outtext(temp);
  547. //Here the midi send function is called by Mick Imfeld
  548.     send_midi(gd.getX(), gd.getY(), gd.getZ(), gd.findNumParts(Fingers::Index));
  549.  
  550. // return to o2glove
  551. }
  552.  
  553. graphicsActor::graphicsActor(InitFile & ini) : hand(ini), drawn(0), xx(0),
  554.     gloveActive(ini.find(title, "gloveActive", 1)),
  555.     handActive(ini.find(title, "handActive",   1)),
  556.     infoActive(ini.find(title, "infoActive",   1)),
  557.     leaveTrails(ini.find(title, "leaveTrails", 0))
  558. {
  559.     int gdriver = DETECT, gmode, errorcode;
  560.  
  561.     // detect graphics hardware available
  562.     detectgraph(&gdriver, &gmode);
  563.     // gdriver now contains detected hardware info.
  564.     // (see graphics_drivers enum type in help)
  565.  
  566.     initgraph(&gdriver, &gmode, NULL);    // detect best graphics mode
  567.     // read result of initialization
  568.     errorcode = graphresult();
  569.  
  570.     if (errorcode != grOk)  // an error occurred
  571.     {
  572.         printf("Graphics error: %s\n", grapherrormsg(errorcode));
  573.         printf("Press any key to halt:");
  574.         getch();
  575.         exit(1);             // exit with error code
  576.     }
  577.     // Ah, hah, hah, hah, hah, hah, hah, HAH!
  578. //    outtext("Press 1, 2, or 3 to select a parallel port.");
  579. }
  580.