home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / progjour / 1991 / 04 / cegdraw.c < prev    next >
Text File  |  1991-04-15  |  14KB  |  324 lines

  1. /* Performs 256-color animation on the Edsun DAC, taking advantage of
  2.    both pixel weighting (selecting pixel colors as weighted averages
  3.    of the colors of nearby pixels) and EDP (the ability to embed
  4.    information in the bitmap that reprograms the DAC's palette during
  5.    the course of each frame). Requires a VGA equipped with an Edsun
  6.    CEG/DAC. All C code compiled with Borland C++ 2.0, operating in C
  7.    mode, and using the small model */
  8.  
  9. #include <conio.h>
  10. #include <dos.h>
  11. #include <stdio.h>
  12. #include <math.h>
  13.  
  14. #define PI  3.141592
  15. #define ADVANCED_8_EDP  15 /* CEG/DAC mode # for Advanced-8 mode with
  16.                               EDP enabled */
  17. #define FRAME_WIDTH 10     /* width of frame around bouncing area */
  18. /* Bounds within which balls bounce */
  19. #define TOP_EDGE  FRAME_WIDTH
  20. #define BOTTOM_EDGE (200-FRAME_WIDTH-1)
  21. #define LEFT_EDGE FRAME_WIDTH
  22. #define RIGHT_EDGE (320-FRAME_WIDTH-1)
  23.  
  24. typedef struct _RGB {   /* defines RGB triplet for a color */
  25.    unsigned char Red;
  26.    unsigned char Green;
  27.    unsigned char Blue;
  28. } RGB;
  29.  
  30. typedef struct _Image {    /* defines a drawable image */
  31.    int Width, Height;      /* dimensions */
  32.    unsigned char *PixMap;  /* image bytes */
  33. } Image;
  34.  
  35. typedef struct _Ball {     /* defines a bouncing ball */
  36.    int X, Y;               /* location */
  37.    int XDir, YDir;         /* direction of movement */
  38.    Image *BallImage;       /* image to draw for ball */
  39. } Ball;
  40.  
  41. int main(void);
  42. int EnableCEGMode(int);
  43. void DrawFrame(int,int);
  44. void SetEDPAtRight(int,RGB*,int,int);
  45. void FillRect(int,int,int,int,int);
  46. void DisableCEGMode(void);
  47. void WaitVerticalSync(void);
  48. void DrawImage(int,int,Image *);
  49. void SetEDPAtLeft(int,int,int,int,int);
  50. void AdvanceAndDrawBalls(Ball**,int);
  51. void Delay(void);
  52. void SetCyclingAttributes(RGB*);
  53. void InitializePalette(void);
  54.  
  55. /* Byte pattern for balls that bounce horizontally */
  56. unsigned char HBallPixMap[] = {
  57.      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  58.      1,  1,  1,  1,  1,  2,  2,  2,  2,  1,  1,  1,  1,  1,
  59.      1,  1,  1,  2,  2,  3,212,208,204,200,218,  1,  1,  1,
  60.      1,  1,  2,  2,  3,214,210,205,200,198,200,220,  1,  1,
  61.      1,  1,  2,  2,  3,216,212,207,202,200,204,218,  1,  1,
  62.      1,  2,  2,  2,  3,218,214,208,206,205,210,216,  2,  1,
  63.      1,  2,  2,  2,  3,220,216,214,212,210,216,220,  2,  1,
  64.      1,  2,  2,  2,  3,222,220,218,216,216,218,222,  2,  1,
  65.      1,  2,  2,  2,  2,  2,  3,221,220,221,  2,  2,  2,  1,
  66.      1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,
  67.      1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,
  68.      1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1,
  69.      1,  1,  1,  1,  1,  2,  2,  2,  2,  1,  1,  1,  1,  1,
  70.      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  71. };
  72. /* Byte pattern for ball that bounces diagonally */
  73. unsigned char DBallPixMap[] = {
  74.      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  75.      1,  1,  1,  1,  1,  4,  4,  4,  4,  1,  1,  1,  1,  1,
  76.      1,  1,  1,  4,  4,  5,212,208,204,200,218,  1,  1,  1,
  77.      1,  1,  4,  4,  5,214,210,205,200,198,200,220,  1,  1,
  78.      1,  1,  4,  4,  5,216,212,207,202,200,204,218,  1,  1,
  79.      1,  4,  4,  4,  5,218,214,208,206,205,210,216,  4,  1,
  80.      1,  4,  4,  4,  5,220,216,214,212,210,216,220,  4,  1,
  81.      1,  4,  4,  4,  5,222,220,218,216,216,218,222,  4,  1,
  82.      1,  4,  4,  4,  4,  4,  5,221,220,221,  4,  4,  4,  1,
  83.      1,  1,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  1,  1,
  84.      1,  1,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  1,  1,
  85.      1,  1,  1,  4,  4,  4,  4,  4,  4,  4,  4,  1,  1,  1,
  86.      1,  1,  1,  1,  1,  4,  4,  4,  4,  1,  1,  1,  1,  1,
  87.      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
  88. };
  89.  
  90. Image HBall = {14,14,HBallPixMap};  /* image for horz bouncing balls */
  91. Image DBall = {14,14,DBallPixMap};  /* image for diag bouncing ball */
  92. Ball Ball1 = {60, 30, -1, 0, &HBall}; /* the four balls to bounce */
  93. Ball Ball2 = {150, 90, 1, 0, &HBall};
  94. Ball Ball3 = {220, 150, -1, 0, &HBall};
  95. Ball Ball4 = {100, 120, -1, -1, &DBall};
  96. Ball* BallArray[] = {&Ball1, &Ball2, &Ball3, &Ball4};
  97. #define NUM_BALLS (sizeof(BallArray)/sizeof(Ball*))
  98.  
  99. int main() {
  100.    int i, GreenTemp, BlueTemp, AttributeStart, FrameCount;
  101.    int FrameDelay, Temp;
  102.    union REGS regset;
  103.    RGB Attribute1Settings[384];  /* used to store the EDP settings for
  104.                                     attribute 1 */
  105.    /* Set to the standard 256-color VGA mode, mode 0x13, 320x200 */
  106.    regset.x.ax = 0x0013; int86(0x10, ®set, ®set);
  107.  
  108.    /* Now enable Advanced-8 CEG mode, so that pixel value 191 becomes
  109.       the EDP opcode, and pixel values 192-223 become pixel weighting
  110.       opcodes */
  111.    if (!EnableCEGMode(ADVANCED_8_EDP)) {
  112.       /* This isn't a CEG/DAC; back to text mode and we're done */
  113.       regset.x.ax = 0x0003; int86(0x10, ®set, ®set);
  114.       fprintf(stderr, "No CEG/DAC installed\n");
  115.       return(1);
  116.    }
  117.  
  118.    InitializePalette();    /* set up the palette */
  119.  
  120.    /* Draw a frame, using the colors 6-190 & 224-255 that we just set
  121.       up to produce a smooth color gradient from top to bottom */
  122.    DrawFrame(6,FRAME_WIDTH);
  123.  
  124.    /* Fill inside the frame with attribute 1, which we'll use EDP to
  125.       change from line to line */
  126.    FillRect(LEFT_EDGE, TOP_EDGE, RIGHT_EDGE+1, BOTTOM_EDGE+1, 1);
  127.  
  128.    /* Set the array of values for EDP loads of attribute 1 and put the
  129.       EDP sequences for the first 200 of those colors at the right
  130.       edge of display memory, in the frame */
  131.    SetCyclingAttributes(Attribute1Settings);
  132.    SetEDPAtRight(1, Attribute1Settings, AttributeStart = 0,
  133.          sizeof(Attribute1Settings)/sizeof(RGB));
  134.  
  135.    /* Set the EDP sequences for the colors of the three horz balls */
  136.    SetEDPAtLeft(2, 0, 0, 0x20, 29);  /* top ball is blue */
  137.    SetEDPAtLeft(3, 0, 0, 0xAF, 30);  /* top ball highlight color */
  138.    SetEDPAtLeft(2, 0, 0x20, 0, 89);  /* middle ball is green */
  139.    SetEDPAtLeft(3, 0, 0x9F, 0, 90);  /* middle ball highlight color */
  140.    SetEDPAtLeft(2, 0x20, 0, 0, 149); /* bottom ball is red */
  141.    SetEDPAtLeft(3, 0xCF, 0, 0, 150); /* bottom ball highlight color */
  142.  
  143.    /* Now cycle through a frame at a time, moving the balls and
  144.       advancing the EDP settings for the background (attribute 1) so
  145.       the background appears to move. Stop when a key is pressed */
  146.    for (FrameCount = FrameDelay = 1; ; ) {   /* draw on first frame */
  147.       WaitVerticalSync();  /* wait until the end of current frame */
  148.       if (--FrameCount == 0) {
  149.          FrameCount = FrameDelay;
  150.          AdvanceAndDrawBalls(BallArray, NUM_BALLS);
  151.  
  152.          /* Change the attribute 1 (background) EDP loads by one
  153.             position in Attribute1Settings, wrapping from start back
  154.             to end. This has the effect of shifting the EDP load of
  155.             attribute 1 with any given color by one scan line, so the
  156.             whole background appears to move one scan line */
  157.          if (AttributeStart == 0)
  158.             AttributeStart = sizeof(Attribute1Settings)/sizeof(RGB)-1;
  159.          else
  160.             AttributeStart--;
  161.          SetEDPAtRight(1, Attribute1Settings, AttributeStart,
  162.                sizeof(Attribute1Settings)/sizeof(RGB));
  163.                          /* set the new attribute 1 EDP sequences */
  164.       }
  165.       if (kbhit()) {
  166.          Temp = getch();
  167.          if ((Temp == 'f') || (Temp == 'F')) {
  168.             if ((FrameDelay -= 5) <= 0) FrameDelay = 1; /* faster */
  169.          } else if ((Temp == 's') || (Temp == 'S')) {
  170.             FrameDelay += 5;  /* slower */
  171.          } else {
  172.             break;   /* done */
  173.          }
  174.       }
  175.    }
  176.  
  177.    DisableCEGMode();
  178.    regset.x.ax = 0x0003; int86(0x10,®set,®set);  /* text mode */
  179.    return(0);
  180. }
  181.  
  182. /* Enables the desired CEG/DAC mode. Returns 1 for success, 0 if no
  183.    CEG/DAC is installed. */
  184. int EnableCEGMode(int mode) {
  185.    WaitVerticalSync();
  186.    /* Write the CEG enable sequence, which is "CEGEDSUN" followed by
  187.       the mode byte, to palette location 222 */
  188.    outp(0x3C7,222); Delay(); outp(0x3C9,'C'); Delay();
  189.    outp(0x3C9,'E'); Delay(); outp(0x3C9,'G'); Delay();
  190.    outp(0x3C7,222); Delay(); outp(0x3C9,'E'); Delay();
  191.    outp(0x3C9,'D'); Delay(); outp(0x3C9,'S'); Delay();
  192.    outp(0x3C7, 222); Delay(); outp(0x3C9,'U'); Delay();
  193.    outp(0x3C9,'N'); Delay();
  194.    outp(0x3C9, mode); Delay();   /* write the CEG mode */
  195.  
  196.    /* At this point, CEG mode should be enabled. Make sure this really
  197.       is a CEG/DAC */
  198.    outp(0x3C6, 0xFF); Delay();   /* enable all DAC mask bits */
  199.    if ((inp(0x3C6) & 0x70) == 0x70)
  200.       return(0);  /* no version # bit is 0; this is not a CEG/DAC */
  201.    else
  202.       return(1);  /* this is a CEG/DAC, and CEG mode is now enabled */
  203. }
  204.  
  205. /* Disable CEG mode by writing to palette location 223 */
  206. void DisableCEGMode() {
  207.    WaitVerticalSync();
  208.    outp(0x3C8, 223); outp(0x3C9, 0); outp(0x3C9, 0); outp(0x3C9, 0);
  209. }
  210.  
  211. /* Wait for the leading edge of vertical sync */
  212. void WaitVerticalSync() {
  213.    while (inp(0x3DA) & 0x08) ;      /* wait for not vertical sync */
  214.    while (!(inp(0x3DA) & 0x08)) ;   /* wait for vertical sync */
  215. }
  216.  
  217. /* Advance each ball and draw it (the blank fringe around each ball
  218.    erases it at the old location) */
  219. void AdvanceAndDrawBalls(Ball** BallPtrPtr, int NumBalls) {
  220.    int i, Temp;
  221.    Ball *BallPtr;
  222.  
  223.    for (i=0; i<NumBalls; i++) {
  224.       BallPtr = *BallPtrPtr++;   /* point to current ball */
  225.       /* Advance the X coordinate, bouncing if frame reached */
  226.       Temp = BallPtr->X + BallPtr->XDir;
  227.       if ((Temp < LEFT_EDGE) ||
  228.             ((Temp + BallPtr->BallImage->Width) > RIGHT_EDGE)) {
  229.          BallPtr->XDir = -BallPtr->XDir;  /* bounce in X dir */
  230.          Temp += BallPtr->XDir;
  231.       }
  232.       BallPtr->X = Temp;
  233.       /* Advance the Y coordinate, bouncing if frame reached */
  234.       Temp = BallPtr->Y + BallPtr->YDir;
  235.       if ((Temp < TOP_EDGE) ||
  236.             ((Temp + BallPtr->BallImage->Height) > BOTTOM_EDGE)) {
  237.          BallPtr->YDir = -BallPtr->YDir;  /* bounce in Y dir */
  238.          Temp += BallPtr->YDir;
  239.       }
  240.       BallPtr->Y = Temp;
  241.       /* Draw the ball at the new location */   
  242.       DrawImage(BallPtr->X, BallPtr->Y, BallPtr->BallImage);
  243.    }
  244. }
  245.  
  246. /* Used to provide a brief delay between OUTs */
  247. void Delay() {
  248. }
  249.  
  250. /* Set AttributeArray to contain a color sequence gradually
  251.    cycling through each primary color */
  252. void SetCyclingAttributes(RGB* AttributeArray) {
  253.    int i;
  254.  
  255.    for (i=0; i<64; i++) {
  256.       AttributeArray[i].Red = i;      /* ascending red */
  257.       AttributeArray[i].Green = 0;
  258.       AttributeArray[i].Blue = 0;
  259.       AttributeArray[i+64].Red = 63-i; /* descending red */
  260.       AttributeArray[i+64].Green = 0;
  261.       AttributeArray[i+64].Blue = 0;
  262.       AttributeArray[i+128].Red = 0;  /* ascending green */
  263.       AttributeArray[i+128].Green = i;
  264.       AttributeArray[i+128].Blue = 0;
  265.       AttributeArray[i+192].Red = 0;  /* descending green */
  266.       AttributeArray[i+192].Green = 63-i;
  267.       AttributeArray[i+192].Blue = 0;
  268.       AttributeArray[i+256].Red = 0;  /* ascending blue */
  269.       AttributeArray[i+256].Green = 0;
  270.       AttributeArray[i+256].Blue = i;
  271.       AttributeArray[i+320].Red = 0;  /* descending blue */
  272.       AttributeArray[i+320].Green = 0;
  273.       AttributeArray[i+320].Blue = 63-i;
  274.    }
  275. }
  276.  
  277. /* Set up the palette with the colors for the outer frame (colors 6
  278.    through 190 and 224 through 255) cycling through combinations of
  279.    the three primary colors as determined by out-of-phase sine waves.
  280.    (There's nothing profound about these colors; it just makes an
  281.    attractive, multicolored border.) Also set attributes 4 and 5 to
  282.    the colors for the ball that bounces diagonally, and sets attrs
  283.    0-3 to black (attributes 1-3 will be altered via EDP later) */
  284. void InitializePalette() {
  285.    int i, ColorEntry;
  286.    RGB PaletteTemp[256];  /* used to pass palette settings to BIOS */
  287.    union REGS regset;
  288.    struct SREGS sregset;
  289.  
  290.    for (i=0; i<4; i++) {
  291.       PaletteTemp[i].Red = 0;    /* black */
  292.       PaletteTemp[i].Green = 0;
  293.       PaletteTemp[i].Blue = 0;
  294.    }
  295.    PaletteTemp[4].Red = 0;     /* the diagonal ball is cyan */
  296.    PaletteTemp[4].Green = 0x20;
  297.    PaletteTemp[4].Blue = 0x20;
  298.    PaletteTemp[5].Red = 0;     /* highlight color for diagonal ball */
  299.    PaletteTemp[5].Green = 0xAF;
  300.    PaletteTemp[5].Blue = 0xAF;
  301.    ColorEntry = 0;
  302.    for (i=6; i<=255; ColorEntry++, i = ((i==190) ? 224 : i+1)) {
  303.                                           /* skip i from 190->224 */
  304.       PaletteTemp[i].Red = abs((int)(255.0 *
  305.             sin((double)(ColorEntry+67)/217.0*PI)));    /* Red */
  306.       PaletteTemp[i].Green = abs((int)(255.0 *
  307.             sin((double)ColorEntry/217.0*PI)));         /* Green */
  308.       PaletteTemp[i].Blue = abs((int)(255.0 *
  309.             sin((double)(ColorEntry+133)/217.0*PI)));   /* Blue */
  310.    }
  311.    regset.x.ax = 0x1012;   /* set block of DAC registers function */
  312.    regset.x.bx = 0;        /* set register 0 first */
  313.    regset.x.cx = 190-0+1;  /* # of registers to set */
  314.    regset.x.dx = (unsigned int)&PaletteTemp[0];
  315.                            /* offset of array from which to set */
  316.    sregset.es = _DS;       /* segment of array from which to set */
  317.    int86x(0x10, ®set, ®set, &sregset); /* attributes 0->190 */
  318.    regset.x.ax = 0x1012;      regset.x.bx = 224;
  319.    regset.x.cx = 255-224+1;   sregset.es = _DS;
  320.    regset.x.dx = (unsigned int)&PaletteTemp[224];
  321.    int86x(0x10, ®set, ®set, &sregset); /* attributes 224->225 */
  322. }
  323.  
  324.