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