home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / qc25 / beispiel / turtle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-25  |  14.7 KB  |  469 lines

  1. /* TURTLE - Modul mit Funktionen zur Ausführung sog. 'Turtle'-Grafik (turtle
  2.  * = Schildkröte). Turtle-Grafik ist ein Modell zum Bestimmen relativer
  3.  * Bewegungen eines vorgestellten Zeigers, dessen Richtung, Farbe,
  4.  * Sichtbarkeit und andere Attribute über Turtle-Funktionen mit Vorgabe-
  5.  * werten versehen werden. Um das Turtle-Modul zu verwenden, schließt man in
  6.  * das betreffende Programm die Einfügdatei TURTLE.H mit ein. Folgende
  7.  * Funktionen (viele davon als Makros definiert) sind global:           
  8.  *
  9.  *   InitTurtle      - Turtle-Grafik anfangen
  10.  *   Home            - Turtle-Vorgabewerte rücksetzen
  11.  *   StiftStatus     - Stift-Sichtbarkeit einrichten
  12.  *   AusFuellung     - Füllstatus einrichten
  13.  *   StiftFarbe      - Stift-Farbindex einrichten
  14.  *   RandFarbe       - Rand-Farbindex einrichten
  15.  *   Schwenken       - Von gegenwärtiger Richtung schwenken
  16.  *   Richtung        - Absolute Richtung einrichten
  17.  *   Bewege          - In gegenwärtige Richtung bewegen
  18.  *   GeheZu          - Zu Absoluter Position gehen
  19.  *   Poly            - Polygon zeichnen
  20.  *   Kreis           - Kreis zeichnen mit Mitte an gegenwärtiger Position
  21.  *   Ellipse         - Ellipse zeichnen mit Mitte an gegenwärtiger Position
  22.  *   Rechteck        - Rechteck zeichnen mit Mitte an gegenwärtiger Position
  23.  *   BildGroesse     - Größe des Rechtecks mit Ausgangspunkt links-oben
  24.  *   BildHolen       - Rechteckiges Bild holen mit Ausgangspunkt links-oben
  25.  *   BildPos         - Rechteckiges Bild anlegen, Ausgangspunkt links-oben
  26.  *   Fuellen         - Von gegenwärtiger Position bis Rand füllen
  27.  *   FarbIndexWeiter - Zum nächsten Farbindex weiter
  28.  *   FarbWertWeiter  - Zum nächsten Farbwert weiter
  29.  *   AufBildsch      - Feststellen: ist gegenwärtige Position auf Bildschirm
  30.  *   RGB             - Rot-, Grün-, Blau-Elemente von Farbwerten kombinieren
  31.  *
  32.  * Die Struktur TURTLE structure, die Globalvariable "tc" (des Typs TURTLE)
  33.  * und die Variable "vlColors" sind definiert. Sie werden jedoch
  34.  * normalerweise nicht direkt vom Programmiere benutzt.
  35.  */
  36.  
  37. #include <graph.h>
  38. #include <math.h>
  39. #include <string.h>
  40. #include "turtle.h"
  41.  
  42. #define PI       3.141593
  43.  
  44. long cvlColors[256];            /* Datenfeld von Farbwerten des Typs long */
  45.  
  46. TURTLE tc = { 1.39 };    /* Ursprüngliches Verhältnis - auf benutzten
  47.                                  * Bildschirm anpassen
  48.                                  */
  49.  
  50. /* InitTurtle - Initialisiert alle Turtle-Vorgabewerte. Diese Funktion
  51.  * sollte mindestens einmal aufgerufen werden (nach _setvideomode und
  52.  * _getvideoconfig) und wieder nach jedem Wechsel auf einen neuen
  53.  * Grafikmodus.
  54.  *
  55.  * Parameter: vc - Zeiger zur Struktur videoconfig
  56.  *
  57.  * Ergebnis:  0 bei Versagen, sonst 1
  58.  *
  59.  * Benutzt:   Strukturvariable tc, Datenfeld cvlColors
  60.  */
  61. short InitTurtle( struct videoconfig *vc )
  62. {
  63.     int i;
  64.     unsigned cvuInc, cvuRot, cvuGruen, cvuBlau;      /* 'Unsigned' Teile der */
  65.     static int mode = -1;                       /*   Farbwerte       */
  66.  
  67.     /* Falls kein Grafikmodus, abbrechen. */
  68.     if( !vc->numxpixels )
  69.         return 0;
  70.  
  71.     /* Nach Moduswechsel Fensterkoordinaten neu einrichten. */
  72.     if( mode != vc->mode )
  73.     {
  74.         mode = vc->mode;
  75.         tc.xsLinks = tc.ysOben = 0;
  76.         tc.xsRechts = vc->numxpixels - 1;
  77.         tc.ysUnten = vc->numypixels - 1;
  78.     }
  79.  
  80.     /* Palettenkennung einrichten. */
  81.     switch( vc->adapter )
  82.     {
  83.         case _MDPA:
  84.         case _CGA:
  85.         case _OCGA:
  86.         case _HGC:
  87.          tc.fPalette = FALSCH;
  88.             break;
  89.         default:
  90.          tc.fPalette = WAHR;
  91.             break;
  92.     }
  93.  
  94.     /* Paletten-Vorgabewerte einrichten. */
  95.     switch( vc->mode )
  96.     {
  97.         case _HRESBW:
  98.         case _HERCMONO:
  99.         case _ERESNOCOLOR:
  100.         case _ORESCOLOR:
  101.         case _VRES2COLOR:
  102.          tc.afw = 0;
  103.          tc.afi = 2;
  104.          return Home();
  105.         case _MRES256COLOR:        /* Aktive Bits in dieser Reihenfolge:  */
  106.             cvuInc = 12;
  107.          tc.afw = tc.afi = 125; /* ???????? ??bbbbbb ??gggggg ??rrrrrr */
  108.             break;
  109.         case _ERESCOLOR:
  110.             if( vc->memory == 64 )
  111.             {
  112.                 cvuInc = 32;
  113.           tc.afw = 16;       /* ???????? ??????Bb ??????Gg ??????Rr */
  114.           tc.afi = 4;
  115.                 break;
  116.             } /* Sonst Rest überspringen */
  117.         case _VRES16COLOR:
  118.             cvuInc = 16;
  119.          tc.afw = 64;           /* ???????? ??????bb ??????gg ??????rr */
  120.          tc.afi = 16;
  121.             break;
  122.         case _MRES4COLOR:
  123.         case _MRESNOCOLOR:
  124.             cvuInc = 32;
  125.          tc.afw = 16;           /* ???????? ??????Bb ??????Gg ??????Rr */
  126.          tc.afi = 4;
  127.             break;
  128.         case _MRES16COLOR:
  129.         case _HRES16COLOR:
  130.             cvuInc = 32;
  131.          tc.afi = tc.afw = 16;  /* ???????? ??????Bb ??????Gg ??????Rr */
  132.             break;
  133.     }
  134.  
  135.     /* Paletten-Datenfelder füllen. */
  136.     for( i = 0, cvuBlau = 0; cvuBlau < 64; cvuBlau += cvuInc )
  137.         for( cvuGruen = 0; cvuGruen < 64; cvuGruen += cvuInc )
  138.             for( cvuRot = 0; cvuRot < 64; cvuRot += cvuInc )
  139.                 {
  140.                     cvlColors[i] = RGB( cvuRot, cvuGruen, cvuBlau );
  141.                     /* Special case of 6 bits for 16 Farbes (RGBI).
  142.                      * If both bits are on for any Farbe, intensity is set.
  143.                      * If one bit is set for a Farbe, that Farbe is on.
  144.                      */
  145.                     if( cvuInc == 32 )
  146.                         cvlColors[i + 8] = cvlColors[i] | (cvlColors[i] >>
  147. 1);
  148.                     i++;
  149.                 }
  150.     cvlColors[tc.afw - 1] = _BRIGHTWHITE;
  151.     FarbWertWeiter( VORGABE );
  152.     return Home();
  153. }
  154.  
  155. /* Home - Zum Rücksetzen der Turtle-Vorgabewerte. Diese Funktion kann
  156.  * aufgerufen werden, solang der Videomodus nicht geändert wurde, doch die
  157.  * Schildkröte ('Turtle') zur Mitte des Fensters zurückgestellt und alle
  158.  * Vorgabewerte rückgesetzt werden sollen. Wenn man beispielsweise die
  159.  * Absolutwerte für das Fenster ändert kann man danach Home aufrufen und
  160.  * damit ein neues Turtle-Fenster einrichten.
  161.  *
  162.  * Parameter: Keine
  163.  *
  164.  * Ergebnis:  0 bei Versagen, sonst 1
  165.  *
  166.  * Benutzt:   tc
  167.  */
  168. short Home()
  169. {
  170.     struct _wxycoord xy1, xy2;
  171.  
  172.     _setviewport( tc.xsLinks, tc.ysOben, tc.xsRechts, tc.ysUnten );
  173.  
  174.     /* Fenster einrichten nach Bildschirmhöhe 1000 und -breite nach
  175.      * Seitenverhältnis.
  176.      */
  177.     tc.yMax = 500.0;
  178.     tc.xMax = tc.yMax * tc.yxSeitenvh;
  179.     if( !_setwindow( FALSCH, -tc.xMax, -tc.yMax, tc.xMax, tc.yMax ) )
  180.         return 0;
  181.  
  182.     /* Über Y-Achse die Größe eines Bildpunkts berechnen. */
  183.     xy1 = _getwindowcoord( 1, 1 );
  184.     xy2 = _getwindowcoord( 1, 2 );
  185.     tc.yEinheit = xy2.wy - xy1.wy;
  186.  
  187.     /* Vorgabewerte für gegenwärtigen Bildpunkt, Richtung, Stift-Status
  188.      * und Füll-Status einrichten.
  189.      */
  190.     tc.xGgw = tc.yGgw = 0.0;
  191.     _moveto_w( tc.xGgw, tc.yGgw );
  192.     Richtung( 0 );
  193.     StiftStatus( WAHR );
  194.     AusFuellung( FALSCH );
  195.  
  196.    /* Weiß zum letzten Farbindex machen; Stift u. Rand darauf einstellen. */
  197.     _remappalette( WEISS, _BRIGHTWHITE );
  198.     RandFarbe( WEISS );
  199.     StiftFarbe( WEISS );
  200.     _setbkcolor( _BLACK );
  201.     return 1;
  202. }
  203.  
  204. /* StiftStatus - Bestimmt die Sichtbarkeit des von Bewege und GeheZu
  205.  * benutzten Stifts. Dieser Status kann WAHR (sichtbar), FALSCH (unsichtbar)
  206.  * oder VORGABE (gegenwärtige Einstellung unverändert).
  207.  *
  208.  * Parameter: fStiftStatus
  209.  *
  210.  * Ergebnis:  gegenwärtiger Stift-Status
  211.  *
  212.  * Benutzt:   tc
  213.  */
  214. int StiftStatus( int fStiftStatus )
  215. {
  216.     switch( fStiftStatus )
  217.     {
  218.      case VORGABE:
  219.             break;
  220.      case FALSCH:
  221.          tc.fStiftStatus = FALSCH;
  222.             break;
  223.         default:
  224.          tc.fStiftStatus = WAHR;
  225.             break;
  226.     }
  227.     return tc.fStiftStatus;
  228. }
  229.  
  230. /* AusFuellung - Bestimmt die Ausfüllweise für Formen, wie z.B. Rechtecke,
  231. und zwar entweder als WAHR (ganz ausfüllen), FALSCH (nur Rand) oder VORGABE
  232. (gegenwärtige Einstellung unverändert).
  233.  *
  234.  * Parameter: fFuell
  235.  *
  236.  * Ergebnis:  Gegenwärtiger Füllstatus
  237.  *
  238.  * Benutzt:   tc
  239.  */
  240. short AusFuellung( short fFuell )
  241. {
  242.     switch( fFuell )
  243.     {
  244.      case VORGABE:
  245.             break;
  246.         case _GBORDER:
  247.      case FALSCH:
  248.             tc.fFuell = _GBORDER;
  249.             break;
  250.         default:
  251.             tc.fFuell = _GFILLINTERIOR;
  252.             break;
  253.     }
  254.     return tc.fFuell;
  255. }
  256.  
  257. /* StiftFarbe - Bestimmt den Farbindex des Stiftes.
  258.  *
  259.  * Parameter: fiGgw - beliebiger VORGABE-Farbindex für unverändertes
  260.  *                    Ergebnis
  261.  *
  262.  * Ergebnis:  gegenwärtiger Stift-Farbindex
  263.  *
  264.  * Benutzt:   tc
  265.  */
  266. short StiftFarbe( short fiGgw )
  267. {
  268.     if( fiGgw != VORGABE )
  269.      _setcolor( tc.fiGgw = fiGgw );
  270.     return tc.fiGgw;
  271. }
  272.  
  273. /* RandFarbe - Bestimmt den Farbindex für den Rand zur Berücksichtigung
  274.  *             durch Füllanweisungen.
  275.  *
  276.  * Parameter: fiRand - beliebiger VORGABE-Farbindex für Ergebnis
  277.  *                     ohne Veränderung
  278.  *
  279.  * Ergebnis:  gegenwärtiger Rand-Farbindex
  280.  *
  281.  * Benutzt:   tc
  282.  */
  283. short RandFarbe( short rand )
  284. {
  285.     if( rand != VORGABE )
  286.      tc.fiRand = rand;
  287.     return tc.fiRand;
  288. }
  289.  
  290. /* Schwenken - Bestimmt neue Richtung relativ zur gegenwärtigen Richtung.
  291.  *
  292. *
  293.  * Parameter: wklGgw - ein Gradwert für Schwenkwinkel, wobei ein positiver
  294.  *            Wert Rechts-, ein negativer Wert eine Linksdrehung bedeutet.
  295.  *
  296.  * Ergebnis:  neuer gegenwärtiger Absolutwert für Richtung
  297.  *
  298.  * Benutzt:   tc
  299.  */
  300. short Schwenken( short wklGgw )
  301. {
  302.     return( tc.wklGgw = ((tc.wklGgw + wklGgw) % CIRCUMFERENCE) );
  303. }
  304.  
  305. /* Richtung - Sets a new absolute Richtung.
  306.  *
  307.  * Parameter: wklGgw - ein Gradwert für Schwenkwinkel, wobei ein positiver
  308.  *            Wert Rechts-, ein negativer Wert eine Linksdrehung bedeutet.
  309.  *            (0 deutet genau nach 'Norden' bzw. 12:00 Uhr.)
  310.  
  311.  * Ergebnis:  neuer gegenwärtiger Absolutwert für Richtung
  312.  *
  313.  * Benutzt:   tc
  314.  */
  315. short Richtung( short wklGgw )
  316. {
  317.     if( wklGgw < 0 )
  318.      return( tc.wklGgw = 360 - (wklGgw % CIRCUMFERENCE) );
  319.     else
  320.      return( tc.wklGgw = wklGgw % CIRCUMFERENCE );
  321. }
  322.  
  323. /* Bewege - Geht von der gegenwärtigen Position eine bestimmte Strecke
  324.  *     in der gegenwärtigen Richtung. Ist Stiftstatus WAHR, wird dabei ein
  325.  *     Strich gezeichnet. Die neue Position wird zur gegenwärtigen Position.
  326.  *
  327.  * Parameter: dxy - Unterschied zwischen gegenwärtigem xy und neuem xy
  328.  *
  329.  * Ergebnis:  0 wenn neue Position außerhalb des Bildschirms liegt, sonst
  330.  *            einen Wert ungleich Null.
  331.  *
  332.  * Benutzt:   tc
  333.  */
  334. short Bewege( double dxy )
  335. {
  336.     double dx, dy;          /* Unterschied zwischen X und Y */
  337.     double angT;
  338.  
  339.     /* Neue X- und Y-Positionen berechnen. */
  340.     angT = (tc.wklGgw - 90) * (PI / HALFCIRCUMFERENCE);
  341.     dx = dxy * cos( angT );
  342.     dy = dxy * sin( angT );
  343.  
  344.     /* Bewegen - dabei zeichnen, wenn Stift WAHR; neue Position einnehmen */
  345.     if( tc.fStiftStatus )
  346.         _lineto_w( tc.xGgw + dx, tc.yGgw + dy );
  347.     else
  348.         _moveto_w( tc.xGgw + dx, tc.yGgw + dy );
  349.     tc.xGgw += dx;
  350.     tc.yGgw += dy;
  351.     return AufBildsch();
  352. }
  353.  
  354. /* GeheZu - Geht von der gegenwärtigen Position zu einer bestimmten
  355.  *          Position. Ist Stiftstatus WAHR, wird dabei ein Strich
  356.  *          gezeichnet. Die neue Position wird zur gegenwärtigen Position.
  357.  *          Die gegenwärtige Richtung ändert sich dabei nicht.
  358.  *
  359.  * Parameter: x und y - Koordinaten der neuen Position
  360.  *
  361.  * Ergebnis:  0 wenn neue Position außerhalb des Bildschirms liegt, sonst
  362.  *            einen Wert ungleich Null.
  363.  *
  364.  * Benutzt:   tc
  365.  */
  366. short GeheZu( double x, double y )
  367. {
  368.     if( tc.fStiftStatus )
  369.         _lineto_w( x, y );
  370.     else
  371.         _moveto_w( x, y );
  372.     tc.xGgw = x;
  373.     tc.yGgw = y;
  374.     return AufBildsch();
  375. }
  376.  
  377. /* Poly - Zeichnet ein Polygon.
  378.  *
  379.  * Parameter: cSide - Seitenanzahl des Polygons
  380.  *            dxySide - Abstand einer jeden Seite
  381.  *
  382.  * Ergebnis:  0 wenn irgend ein Teil des Polygons außerhalb des Bildschirms
  383.  *            liegt, sonst einen Wert ungleich Null.
  384.  */
  385. short Poly( int cSide, double dxySide )
  386. {
  387.     short i, angT, fPen, ret = WAHR;
  388.  
  389.  /* Sicherstellen, daß Stift aktiv (WAHR) ist (danach wieder rücksetzen). */
  390.     fPen = StiftStatus( WAHR );
  391.  
  392.     /* Richtung (Winkel) berechnen, dann jede Seite zeichnen. */
  393.     angT = 360 / cSide;
  394.     for( i = 1; i <= cSide; i++ )
  395.     {
  396.         ret = Bewege( dxySide ) && ret;
  397.         Schwenken( angT );
  398.     }
  399.     StiftStatus( fPen );
  400.     return ret;
  401. }
  402.  
  403. /* FarbIndexWeiter - Zum nächsten Farbindex weiterrotieren. Das erste
  404.  * Attribut (meist der Hintergund) und das letzte (weiß) werden ausgelassen.
  405.  *
  406.  * Parameter: fiGgw - Mit VORGABE den Farbindex vom letzten Aufruf benutzen
  407.  *            oder eine neue Farbe als Ausgangspunlkt bestimmen.
  408.  *
  409.  * Ergebnis:  Der weiterrotierte Farbindex
  410.  *
  411.  * Benutzt:   tc
  412.  */
  413. short FarbIndexWeiter( short fiGgw )
  414. {
  415.     static short fiPrev = 0;    /* Statisch, damit der Index zwischen
  416.                                  * Aufrufen beibehalten wird
  417.                                  */
  418.     /* Neuen gegenwärtigen Index zuweisen, falls gegeben. */
  419.     if( fiGgw != VORGABE )
  420.      fiPrev = fiGgw;
  421.  
  422.     /* Für zweifarbiges Video umschalten, für mehrfarbiges rotieren. */
  423.     if( tc.afi == 2 )
  424.      return( fiPrev = !fiPrev );
  425.     else
  426.      return( fiPrev = (++fiPrev % (tc.afi - 1)) );
  427. }
  428.  
  429. /* FarbWertWeiter - Zum nächsten Farbwert weiterrotieren für Adapter (EGA
  430.  * und höher), die mit umkonfigurierbaren Paletten funktionieren.
  431.  *
  432.  * Parameter: fAktion - VORGABE (alle weiterdrehen) oder LIMITED (nur
  433.  *                      die ersten 14)
  434.  *
  435.  * Ergebnis:  Keines
  436.  *
  437.  * Benutzt:   tc
  438.  */
  439. void FarbWertWeiter( int fAktion )
  440. {
  441.     static int icvGgw = 1;  /* Gegenwärtiger Index zum Farbwert-Datenfeld */
  442.     static int fiGgw = 1;   /* Gegenwärtiger Farbindex                    */
  443.     int icvT;               /* Vorläufiger Index zu Farbwerten            */
  444.     int i;
  445.  
  446.     /* Betriebsarten ohne Palettenwerte ignorieren. */
  447.     if( !tc.fPalette || !tc.afw )
  448.         return;
  449.  
  450.     /* Farbwert-Index erhöhen und weiterrotieren. */
  451.     icvT = (++icvGgw % (tc.afw - 2)) + 1;
  452.  
  453.  
  454.     /* VORGABE - Alle Farbindeces in Gruppen von je 14 weiterrotieren. Für
  455.      * die meisten Betriebsarten sund dies schon alle Indeces mit Ausnahme
  456.      * des ersten und letzten. Bei 256-Farbmodus würde das Rotieren aller
  457.      * verfügbaren Indeces zu lange dauern.
  458.      */
  459.     if( fAktion == VORGABE )
  460.         for( i = 1; i <= 14; i++ )
  461.          _remappalette( (fiGgw++ % (tc.afi - 2)) + 1,
  462.                   cvlColors[(icvT++ % (tc.afw - 2)) + 1] );
  463.  
  464.     /* LIMITED - Nur die ersten 14 Farbindeces rotieren. */
  465.     else
  466.         for( i = 1; i <= 14; i++ )
  467.          _remappalette( i, cvlColors[(icvT++ % (tc.afw - 1)) + 1] );
  468. }
  469.